Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwidgettextcontrol.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#ifndef QT_NO_TEXTCONTROL
8
9#include <qfont.h>
10#include <qpainter.h>
11#include <qevent.h>
12#include <qdebug.h>
13#if QT_CONFIG(draganddrop)
14#include <qdrag.h>
15#endif
16#include <qclipboard.h>
17#include <qstyle.h>
18#include <qtimer.h>
19#include "private/qapplication_p.h"
20#include "private/qtextdocumentlayout_p.h"
21#include "private/qabstracttextdocumentlayout_p.h"
22#if QT_CONFIG(menu)
23#include "private/qmenu_p.h"
24#endif
25#include "qtextdocument.h"
26#include "private/qtextdocument_p.h"
27#include "private/qtextdocumentfragment_p.h"
28#include "qtextlist.h"
29#include "private/qwidgettextcontrol_p.h"
30#if QT_CONFIG(style_stylesheet)
31# include "private/qstylesheetstyle_p.h"
32#endif
33#if QT_CONFIG(graphicsview)
34#include "qgraphicssceneevent.h"
35#endif
36#include "qpagedpaintdevice.h"
37#include "private/qpagedpaintdevice_p.h"
38#include "qtextdocumentwriter.h"
39#include "qstylehints.h"
40#include "private/qtextcursor_p.h"
41
42#include <qtextformat.h>
43#include <qdatetime.h>
44#include <qbuffer.h>
45#include <qapplication.h>
46#include <limits.h>
47#include <qtexttable.h>
48#include <qvariant.h>
49#include <qurl.h>
50#include <qdesktopservices.h>
51#include <qinputmethod.h>
52#if QT_CONFIG(tooltip)
53#include <qtooltip.h>
54#endif
55#include <qstyleoption.h>
56#if QT_CONFIG(lineedit)
57#include <QtWidgets/qlineedit.h>
58#endif
59#include <QtGui/qaccessible.h>
60#include <QtCore/qmetaobject.h>
61
62#if QT_CONFIG(shortcut)
63#include "private/qapplication_p.h"
64#include "private/qshortcutmap_p.h"
65#include <qkeysequence.h>
66#define ACCEL_KEY(k) (!QCoreApplication::testAttribute(Qt::AA_DontShowShortcutsInContextMenus) \
67 && !QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(k) ? \
68 u'\t' + QKeySequence(k).toString(QKeySequence::NativeText) : QString())
69
70#else
71#define ACCEL_KEY(k) QString()
72#endif
73
74#include <algorithm>
75
77
78using namespace Qt::StringLiterals;
79
80// could go into QTextCursor...
82{
83 const QTextBlock block = cursor.block();
84 if (!block.isValid())
85 return QTextLine();
86
87 const QTextLayout *layout = block.layout();
88 if (!layout)
89 return QTextLine();
90
91 const int relativePos = cursor.position() - block.position();
92 return layout->lineForTextPosition(relativePos);
93}
94
96 : doc(nullptr), cursorOn(false), cursorVisible(false), cursorIsFocusIndicator(false),
97#ifndef Q_OS_ANDROID
98 interactionFlags(Qt::TextEditorInteraction),
99#else
100 interactionFlags(Qt::TextEditable | Qt::TextSelectableByKeyboard),
101#endif
102 dragEnabled(true),
103#if QT_CONFIG(draganddrop)
104 mousePressed(false), mightStartDrag(false),
105#endif
106 lastSelectionPosition(0), lastSelectionAnchor(0),
107 ignoreAutomaticScrollbarAdjustement(false),
108 overwriteMode(false),
109 acceptRichText(true),
110 preeditCursor(0), hideCursor(false),
111 hasFocus(false),
112#ifdef QT_KEYPAD_NAVIGATION
113 hasEditFocus(false),
114#endif
115 isEnabled(true),
116 hadSelectionOnMousePress(false),
117 ignoreUnusedNavigationEvents(false),
118 openExternalLinks(false),
119 wordSelectionEnabled(false)
120{}
121
123{
124#ifdef QT_NO_SHORTCUT
125 Q_UNUSED(e);
126#endif
127
129 if (cursor.isNull())
130 return false;
131
132 const QTextCursor oldSelection = cursor;
133 const int oldCursorPos = cursor.position();
134
137
138 if (false) {
139 }
140#ifndef QT_NO_SHORTCUT
143 }
144 else if (e == QKeySequence::MoveToPreviousChar) {
146 }
147 else if (e == QKeySequence::SelectNextChar) {
150 }
151 else if (e == QKeySequence::SelectPreviousChar) {
154 }
155 else if (e == QKeySequence::SelectNextWord) {
158 }
159 else if (e == QKeySequence::SelectPreviousWord) {
162 }
163 else if (e == QKeySequence::SelectStartOfLine) {
166 }
167 else if (e == QKeySequence::SelectEndOfLine) {
170 }
171 else if (e == QKeySequence::SelectStartOfBlock) {
174 }
175 else if (e == QKeySequence::SelectEndOfBlock) {
178 }
182 }
183 else if (e == QKeySequence::SelectEndOfDocument) {
184 op = QTextCursor::End;
186 }
187 else if (e == QKeySequence::SelectPreviousLine) {
188 op = QTextCursor::Up;
190 {
191 QTextBlock block = cursor.block();
193 if (!block.previous().isValid()
194 && line.isValid()
195 && line.lineNumber() == 0)
197 }
198 }
199 else if (e == QKeySequence::SelectNextLine) {
202 {
203 QTextBlock block = cursor.block();
205 if (!block.next().isValid()
206 && line.isValid()
207 && line.lineNumber() == block.layout()->lineCount() - 1)
208 op = QTextCursor::End;
209 }
210 }
211 else if (e == QKeySequence::MoveToNextWord) {
213 }
214 else if (e == QKeySequence::MoveToPreviousWord) {
216 }
217 else if (e == QKeySequence::MoveToEndOfBlock) {
219 }
220 else if (e == QKeySequence::MoveToStartOfBlock) {
222 }
223 else if (e == QKeySequence::MoveToNextLine) {
225 }
226 else if (e == QKeySequence::MoveToPreviousLine) {
227 op = QTextCursor::Up;
228 }
229 else if (e == QKeySequence::MoveToStartOfLine) {
231 }
232 else if (e == QKeySequence::MoveToEndOfLine) {
234 }
237 }
238 else if (e == QKeySequence::MoveToEndOfDocument) {
239 op = QTextCursor::End;
240 }
241#endif // QT_NO_SHORTCUT
242 else {
243 return false;
244 }
245
246// Except for pageup and pagedown, OS X has very different behavior, we don't do it all, but
247// here's the breakdown:
248// Shift still works as an anchor, but only one of the other keys can be down Ctrl (Command),
249// Alt (Option), or Meta (Control).
250// Command/Control + Left/Right -- Move to left or right of the line
251// + Up/Down -- Move to top bottom of the file. (Control doesn't move the cursor)
252// Option + Left/Right -- Move one word Left/right.
253// + Up/Down -- Begin/End of Paragraph.
254// Home/End Top/Bottom of file. (usually don't move the cursor, but will select)
255
256 bool visualNavigation = cursor.visualNavigation();
258 const bool moved = cursor.movePosition(op, mode);
259 cursor.setVisualNavigation(visualNavigation);
260 q->ensureCursorVisible();
261
262 bool ignoreNavigationEvents = ignoreUnusedNavigationEvents;
263 bool isNavigationEvent = e->key() == Qt::Key_Up || e->key() == Qt::Key_Down;
264
265#ifdef QT_KEYPAD_NAVIGATION
266 ignoreNavigationEvents = ignoreNavigationEvents || QApplicationPrivate::keypadNavigationEnabled();
267 isNavigationEvent = isNavigationEvent ||
268 (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
269 && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right));
270#else
271 isNavigationEvent = isNavigationEvent || e->key() == Qt::Key_Left || e->key() == Qt::Key_Right;
272#endif
273
274 if (moved) {
275 if (cursor.position() != oldCursorPos)
276 emit q->cursorPositionChanged();
277 emit q->microFocusChanged();
278 } else if (ignoreNavigationEvents && isNavigationEvent && oldSelection.anchor() == cursor.anchor()) {
279 return false;
280 }
281
282 selectionChanged(/*forceEmitSelectionChanged =*/(mode == QTextCursor::KeepAnchor));
283
284 repaintOldAndNewSelection(oldSelection);
285
286 return true;
287}
288
290{
292
294 if (fmt == lastCharFormat)
295 return;
297
298 emit q->currentCharFormatChanged(fmt);
299 emit q->microFocusChanged();
300}
301
303{
305
307 if (!list) {
308 QTextBlockFormat modifier;
309 modifier.setIndent(blockFmt.indent() + 1);
310 cursor.mergeBlockFormat(modifier);
311 } else {
312 QTextListFormat format = list->format();
313 format.setIndent(format.indent() + 1);
314
315 if (list->itemNumber(cursor.block()) == 1)
316 list->setFormat(format);
317 else
319 }
320}
321
323{
325
327
328 if (!list) {
329 QTextBlockFormat modifier;
330 modifier.setIndent(blockFmt.indent() - 1);
331 cursor.mergeBlockFormat(modifier);
332 } else {
333 QTextListFormat listFmt = list->format();
334 listFmt.setIndent(listFmt.indent() - 1);
335 list->setFormat(listFmt);
336 }
337}
338
340{
342 QTextTableCell cell = table->cellAt(cursor);
343
344 int newColumn = cell.column() + cell.columnSpan();
345 int newRow = cell.row();
346
347 if (newColumn >= table->columns()) {
348 newColumn = 0;
349 ++newRow;
350 if (newRow >= table->rows())
351 table->insertRows(table->rows(), 1);
352 }
353
354 cell = table->cellAt(newRow, newColumn);
356}
357
359{
361 QTextTableCell cell = table->cellAt(cursor);
362
363 int newColumn = cell.column() - 1;
364 int newRow = cell.row();
365
366 if (newColumn < 0) {
367 newColumn = table->columns() - 1;
368 --newRow;
369 if (newRow < 0)
370 return;
371 }
372
373 cell = table->cellAt(newRow, newColumn);
375}
376
378{
380
382
383 QTextListFormat listFmt;
385 listFmt.setIndent(blockFmt.indent() + 1);
386
387 blockFmt.setIndent(0);
388 cursor.setBlockFormat(blockFmt);
389
390 cursor.createList(listFmt);
391
393}
394
396{
398 setContent(format, text, document);
399
401 q->setCursorWidth(-1);
402}
403
405{
407
408 // for use when called from setPlainText. we may want to re-use the currently
409 // set char format then.
410 const QTextCharFormat charFormatForInsertion = cursor.charFormat();
411
412 bool clearDocument = true;
413 if (!doc) {
414 if (document) {
415 doc = document;
416 } else {
417 palette = QApplication::palette("QWidgetTextControl");
418 doc = new QTextDocument(q);
419 }
420 clearDocument = false;
423
424// #### doc->documentLayout()->setPaintDevice(viewport);
425
432
433 // convenience signal forwards
440 }
441
442 bool previousUndoRedoState = doc->isUndoRedoEnabled();
443 if (!document)
444 doc->setUndoRedoEnabled(false);
445
446 //Saving the index save some time.
447 static int contentsChangedIndex = QMetaMethod::fromSignal(&QTextDocument::contentsChanged).methodIndex();
448 static int textChangedIndex = QMetaMethod::fromSignal(&QWidgetTextControl::textChanged).methodIndex();
449 // avoid multiple textChanged() signals being emitted
450 QMetaObject::disconnect(doc, contentsChangedIndex, q, textChangedIndex);
451
452 if (!text.isEmpty()) {
453 // clear 'our' cursor for insertion to prevent
454 // the emission of the cursorPositionChanged() signal.
455 // instead we emit it only once at the end instead of
456 // at the end of the document after loading and when
457 // positioning the cursor again to the start of the
458 // document.
460 if (format == Qt::PlainText) {
461 QTextCursor formatCursor(doc);
462 // put the setPlainText and the setCharFormat into one edit block,
463 // so that the syntax highlight triggers only /once/ for the entire
464 // document, not twice.
465 formatCursor.beginEditBlock();
467 doc->setUndoRedoEnabled(false);
468 formatCursor.select(QTextCursor::Document);
469 formatCursor.setCharFormat(charFormatForInsertion);
470 formatCursor.endEditBlock();
471#if QT_CONFIG(textmarkdownreader)
472 } else if (format == Qt::MarkdownText) {
473 doc->setMarkdown(text);
474 doc->setUndoRedoEnabled(false);
475#endif
476 } else {
477#ifndef QT_NO_TEXTHTMLPARSER
478 doc->setHtml(text);
479#else
481#endif
482 doc->setUndoRedoEnabled(false);
483 }
485 } else if (clearDocument) {
486 doc->clear();
487 }
488 cursor.setCharFormat(charFormatForInsertion);
489
490 QMetaObject::connect(doc, contentsChangedIndex, q, textChangedIndex);
491 emit q->textChanged();
492 if (!document)
493 doc->setUndoRedoEnabled(previousUndoRedoState);
495 if (!document)
496 doc->setModified(false);
497
498 q->ensureCursorVisible();
499 emit q->cursorPositionChanged();
500
503}
504
506{
507#if QT_CONFIG(draganddrop)
509 mousePressed = false;
510 if (!contextWidget)
511 return;
512 QMimeData *data = q->createMimeDataFromSelection();
513
514 QDrag *drag = new QDrag(contextWidget);
515 drag->setMimeData(data);
516
517 Qt::DropActions actions = Qt::CopyAction;
518 Qt::DropAction action;
520 actions |= Qt::MoveAction;
521 action = drag->exec(actions, Qt::MoveAction);
522 } else {
523 action = drag->exec(actions, Qt::CopyAction);
524 }
525
526 if (action == Qt::MoveAction && drag->target() != contextWidget)
528#endif
529}
530
532{
534 const int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
535 if (cursorPos == -1)
536 return;
537 cursor.setPosition(cursorPos);
538}
539
549
555
557{
559 if (cursor.hasSelection()
560 && oldSelection.hasSelection()
561 && cursor.currentFrame() == oldSelection.currentFrame()
563 && !oldSelection.hasComplexSelection()
564 && cursor.anchor() == oldSelection.anchor()
565 ) {
566 QTextCursor differenceSelection(doc);
567 differenceSelection.setPosition(oldSelection.position());
568 differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor);
569 emit q->updateRequest(q->selectionRect(differenceSelection));
570 } else {
571 if (!oldSelection.isNull())
572 emit q->updateRequest(q->selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection));
573 emit q->updateRequest(q->selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor));
574 }
575}
576
577void QWidgetTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged /*=false*/)
578{
580 if (forceEmitSelectionChanged) {
581 emit q->selectionChanged();
582#if QT_CONFIG(accessibility)
583 if (q->parent() && q->parent()->isWidgetType()) {
584 QAccessibleTextSelectionEvent ev(q->parent(), cursor.anchor(), cursor.position());
585 QAccessible::updateAccessibility(&ev);
586 }
587#endif
588 }
589
592 return;
593
594 bool selectionStateChange = (cursor.hasSelection()
596 if (selectionStateChange)
597 emit q->copyAvailable(cursor.hasSelection());
598
599 if (!forceEmitSelectionChanged
600 && (selectionStateChange
601 || (cursor.hasSelection()
603 || cursor.anchor() != lastSelectionAnchor)))) {
604 emit q->selectionChanged();
605#if QT_CONFIG(accessibility)
606 if (q->parent() && q->parent()->isWidgetType()) {
607 QAccessibleTextSelectionEvent ev(q->parent(), cursor.anchor(), cursor.position());
608 QAccessible::updateAccessibility(&ev);
609 }
610#endif
611 }
612 emit q->microFocusChanged();
615}
616
622
623#ifndef QT_NO_CLIPBOARD
625{
627 if (!cursor.hasSelection() || !clipboard->supportsSelection())
628 return;
630 QMimeData *data = q->createMimeDataFromSelection();
632}
633#endif
634
636{
638 if (someCursor.isCopyOf(cursor)) {
639 emit q->cursorPositionChanged();
640 emit q->microFocusChanged();
641 }
642}
643
644void QWidgetTextControlPrivate::_q_contentsChanged(int from, int charsRemoved, int charsAdded)
645{
646#if QT_CONFIG(accessibility)
648
649 if (QAccessible::isActive() && q->parent() && q->parent()->isWidgetType()) {
650 QTextCursor tmp(doc);
651 tmp.setPosition(from);
652 // when setting a new text document the length is off
653 // QTBUG-32583 - characterCount is off by 1 requires the -1
654 tmp.setPosition(qMin(doc->characterCount() - 1, from + charsAdded), QTextCursor::KeepAnchor);
655 QString newText = tmp.selectedText();
656
657 // always report the right number of removed chars, but in lack of the real string use spaces
658 QString oldText = QString(charsRemoved, u' ');
659
660 QAccessibleEvent *ev = nullptr;
661 if (charsRemoved == 0) {
662 ev = new QAccessibleTextInsertEvent(q->parent(), from, newText);
663 } else if (charsAdded == 0) {
664 ev = new QAccessibleTextRemoveEvent(q->parent(), from, oldText);
665 } else {
666 ev = new QAccessibleTextUpdateEvent(q->parent(), from, oldText, newText);
667 }
668 QAccessible::updateAccessibility(ev);
669 delete ev;
670 }
671#else
672 Q_UNUSED(from);
673 Q_UNUSED(charsRemoved);
674 Q_UNUSED(charsAdded);
675#endif
676}
677
689
703
705{
707 if (cursorVisible) {
708 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
709 if (flashTime >= 2)
710 cursorBlinkTimer.start(flashTime / 2, q_func());
711 }
712
715}
716
717void QWidgetTextControlPrivate::extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition)
718{
720
721 // if inside the initial selected word keep that
722 if (suggestedNewPosition >= selectedWordOnDoubleClick.selectionStart()
723 && suggestedNewPosition <= selectedWordOnDoubleClick.selectionEnd()) {
724 q->setTextCursor(selectedWordOnDoubleClick);
725 return;
726 }
727
729 curs.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
730
732 return;
733 const int wordStartPos = curs.position();
734
735 const int blockPos = curs.block().position();
736 const QPointF blockCoordinates = q->blockBoundingRect(curs.block()).topLeft();
737
739 if (!line.isValid())
740 return;
741
742 const qreal wordStartX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
743
745 return;
746 const int wordEndPos = curs.position();
747
748 const QTextLine otherLine = currentTextLine(curs);
749 if (otherLine.textStart() != line.textStart()
750 || wordEndPos == wordStartPos)
751 return;
752
753 const qreal wordEndX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
754
755 if (!wordSelectionEnabled && (mouseXPosition < wordStartX || mouseXPosition > wordEndX))
756 return;
757
759 if (suggestedNewPosition < selectedWordOnDoubleClick.position()) {
762 } else {
765 }
766 } else {
767 // keep the already selected word even when moving to the left
768 // (#39164)
769 if (suggestedNewPosition < selectedWordOnDoubleClick.position())
771 else
773
774 const qreal differenceToStart = mouseXPosition - wordStartX;
775 const qreal differenceToEnd = wordEndX - mouseXPosition;
776
777 if (differenceToStart < differenceToEnd)
779 else
781 }
782
784#ifndef QT_NO_CLIPBOARD
786#endif
787 selectionChanged(true);
788 }
789}
790
792{
794
795 // if inside the initial selected line keep that
796 if (suggestedNewPosition >= selectedBlockOnTrippleClick.selectionStart()
797 && suggestedNewPosition <= selectedBlockOnTrippleClick.selectionEnd()) {
798 q->setTextCursor(selectedBlockOnTrippleClick);
799 return;
800 }
801
802 if (suggestedNewPosition < selectedBlockOnTrippleClick.position()) {
804 cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
806 } else {
808 cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
811 }
812
814#ifndef QT_NO_CLIPBOARD
816#endif
817 selectionChanged(true);
818 }
819}
820
827
829{
831 d->repaintSelection();
832 const int oldCursorPos = d->cursor.position();
833 d->doc->undo(&d->cursor);
834 if (d->cursor.position() != oldCursorPos)
838}
839
841{
843 d->repaintSelection();
844 const int oldCursorPos = d->cursor.position();
845 d->doc->redo(&d->cursor);
846 if (d->cursor.position() != oldCursorPos)
850}
851
858
865
872
876
878{
880 if (d->doc == document)
881 return;
882
883 d->doc->disconnect(this);
884 d->doc->documentLayout()->disconnect(this);
885 d->doc->documentLayout()->setPaintDevice(nullptr);
886
887 if (d->doc->parent() == this)
888 delete d->doc;
889
890 d->doc = nullptr;
891 d->setContent(Qt::RichText, QString(), document);
892}
893
895{
896 Q_D(const QWidgetTextControl);
897 return d->doc;
898}
899
900void QWidgetTextControl::setTextCursor(const QTextCursor &cursor, bool selectionClipboard)
901{
903 d->cursorIsFocusIndicator = false;
904 const bool posChanged = cursor.position() != d->cursor.position();
905 const QTextCursor oldSelection = d->cursor;
906 d->cursor = cursor;
907 d->cursorOn = d->hasFocus
908 && (d->interactionFlags & (Qt::TextSelectableByKeyboard | Qt::TextEditable));
909 d->_q_updateCurrentCharFormatAndSelection();
911 d->repaintOldAndNewSelection(oldSelection);
912 if (posChanged)
914
915#ifndef QT_NO_CLIPBOARD
916 if (selectionClipboard)
917 d->setClipboardSelection();
918#else
919 Q_UNUSED(selectionClipboard);
920#endif
921}
922
924{
925 Q_D(const QWidgetTextControl);
926 return d->cursor;
927}
928
929#ifndef QT_NO_CLIPBOARD
930
932{
934 if (!(d->interactionFlags & Qt::TextEditable) || !d->cursor.hasSelection())
935 return;
936 copy();
937 d->cursor.removeSelectedText();
938}
939
941{
943 if (!d->cursor.hasSelection())
944 return;
946 QGuiApplication::clipboard()->setMimeData(data);
947}
948
950{
951 const QMimeData *md = QGuiApplication::clipboard()->mimeData(mode);
952 if (md)
954}
955#endif
956
958{
960 // clears and sets empty content
961 d->extraSelections.clear();
962 d->setContent();
963}
964
965
967{
969 const int selectionLength = qAbs(d->cursor.position() - d->cursor.anchor());
970 const int oldCursorPos = d->cursor.position();
971 d->cursor.select(QTextCursor::Document);
972 d->selectionChanged(selectionLength != qAbs(d->cursor.position() - d->cursor.anchor()));
973 d->cursorIsFocusIndicator = false;
974 if (d->cursor.position() != oldCursorPos)
977}
978
979void QWidgetTextControl::processEvent(QEvent *e, const QPointF &coordinateOffset, QWidget *contextWidget)
980{
982 t.translate(coordinateOffset.x(), coordinateOffset.y());
983 processEvent(e, t, contextWidget);
984}
985
987{
989 if (d->interactionFlags == Qt::NoTextInteraction) {
990 e->ignore();
991 return;
992 }
993
994 d->contextWidget = contextWidget;
995
996 if (!d->contextWidget) {
997 switch (e->type()) {
998#if QT_CONFIG(graphicsview)
1012 QGraphicsSceneEvent *ev = static_cast<QGraphicsSceneEvent *>(e);
1013 d->contextWidget = ev->widget();
1014 break;
1015 }
1016#endif // QT_CONFIG(graphicsview)
1017 default: break;
1018 };
1019 }
1020
1021 switch (e->type()) {
1022 case QEvent::KeyPress:
1023 d->keyPressEvent(static_cast<QKeyEvent *>(e));
1024 break;
1026 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
1027 d->mousePressEvent(ev, ev->button(), transform.map(ev->position().toPoint()), ev->modifiers(),
1028 ev->buttons(), ev->globalPosition().toPoint());
1029 break; }
1030 case QEvent::MouseMove: {
1031 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
1032 d->mouseMoveEvent(ev, ev->button(), transform.map(ev->position().toPoint()), ev->modifiers(),
1033 ev->buttons(), ev->globalPosition().toPoint());
1034 break; }
1036 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
1037 d->mouseReleaseEvent(ev, ev->button(), transform.map(ev->position().toPoint()), ev->modifiers(),
1038 ev->buttons(), ev->globalPosition().toPoint());
1039 break; }
1041 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
1042 d->mouseDoubleClickEvent(ev, ev->button(), transform.map(ev->position().toPoint()), ev->modifiers(),
1043 ev->buttons(), ev->globalPosition().toPoint());
1044 break; }
1046 d->inputMethodEvent(static_cast<QInputMethodEvent *>(e));
1047 break;
1048#ifndef QT_NO_CONTEXTMENU
1049 case QEvent::ContextMenu: {
1050 QContextMenuEvent *ev = static_cast<QContextMenuEvent *>(e);
1051 d->contextMenuEvent(ev->globalPos(), transform.map(ev->pos()), contextWidget);
1052 break; }
1053#endif // QT_NO_CONTEXTMENU
1054 case QEvent::FocusIn:
1055 case QEvent::FocusOut:
1056 d->focusEvent(static_cast<QFocusEvent *>(e));
1057 break;
1058
1060 d->isEnabled = e->isAccepted();
1061 break;
1062
1063#if QT_CONFIG(tooltip)
1064 case QEvent::ToolTip: {
1065 QHelpEvent *ev = static_cast<QHelpEvent *>(e);
1066 d->showToolTip(ev->globalPos(), transform.map(ev->pos()), contextWidget);
1067 break;
1068 }
1069#endif // QT_CONFIG(tooltip)
1070
1071#if QT_CONFIG(draganddrop)
1072 case QEvent::DragEnter: {
1073 QDragEnterEvent *ev = static_cast<QDragEnterEvent *>(e);
1074 if (d->dragEnterEvent(e, ev->mimeData()))
1075 ev->acceptProposedAction();
1076 break;
1077 }
1078 case QEvent::DragLeave:
1079 d->dragLeaveEvent();
1080 break;
1081 case QEvent::DragMove: {
1082 QDragMoveEvent *ev = static_cast<QDragMoveEvent *>(e);
1083 if (d->dragMoveEvent(e, ev->mimeData(), transform.map(ev->position().toPoint())))
1084 ev->acceptProposedAction();
1085 break;
1086 }
1087 case QEvent::Drop: {
1088 QDropEvent *ev = static_cast<QDropEvent *>(e);
1089 if (d->dropEvent(ev->mimeData(), transform.map(ev->position().toPoint()), ev->dropAction(), ev->source()))
1090 ev->acceptProposedAction();
1091 break;
1092 }
1093#endif
1094
1095#if QT_CONFIG(graphicsview)
1097 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1098 d->mousePressEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
1099 ev->screenPos());
1100 break; }
1102 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1103 d->mouseMoveEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
1104 ev->screenPos());
1105 break; }
1107 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1108 d->mouseReleaseEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
1109 ev->screenPos());
1110 break; }
1112 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1113 d->mouseDoubleClickEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
1114 ev->screenPos());
1115 break; }
1118 d->contextMenuEvent(ev->screenPos(), transform.map(ev->pos()), contextWidget);
1119 break; }
1120
1122 QGraphicsSceneHoverEvent *ev = static_cast<QGraphicsSceneHoverEvent *>(e);
1123 d->mouseMoveEvent(ev, Qt::NoButton, transform.map(ev->pos()), ev->modifiers(),Qt::NoButton,
1124 ev->screenPos());
1125 break; }
1126
1129 if (d->dragEnterEvent(e, ev->mimeData()))
1131 break; }
1133 d->dragLeaveEvent();
1134 break;
1137 if (d->dragMoveEvent(e, ev->mimeData(), transform.map(ev->pos())))
1139 break; }
1142 if (d->dropEvent(ev->mimeData(), transform.map(ev->pos()), ev->dropAction(), ev->source()))
1143 ev->accept();
1144 break; }
1145#endif // QT_CONFIG(graphicsview)
1146#ifdef QT_KEYPAD_NAVIGATION
1147 case QEvent::EnterEditFocus:
1148 case QEvent::LeaveEditFocus:
1149 if (QApplicationPrivate::keypadNavigationEnabled())
1150 d->editFocusEvent(e);
1151 break;
1152#endif
1154 if (d->interactionFlags & Qt::TextEditable) {
1155 QKeyEvent* ke = static_cast<QKeyEvent *>(e);
1157 ke->accept();
1158 }
1159 break;
1160 default:
1161 break;
1162 }
1163}
1164
1166{
1167 return QObject::event(e);
1168}
1169
1171{
1172 Q_D(QWidgetTextControl);
1173 if (e->timerId() == d->cursorBlinkTimer.timerId()) {
1174 d->cursorOn = !d->cursorOn;
1175
1176 if (d->cursor.hasSelection())
1178 != 0);
1179
1180 d->repaintCursor();
1181 } else if (e->timerId() == d->trippleClickTimer.timerId()) {
1182 d->trippleClickTimer.stop();
1183 }
1184}
1185
1187{
1188 Q_D(QWidgetTextControl);
1189 d->setContent(Qt::PlainText, text);
1190}
1191
1192#if QT_CONFIG(textmarkdownreader)
1193void QWidgetTextControl::setMarkdown(const QString &text)
1194{
1195 Q_D(QWidgetTextControl);
1196 d->setContent(Qt::MarkdownText, text);
1197}
1198#endif
1199
1201{
1202 Q_D(QWidgetTextControl);
1203 d->setContent(Qt::RichText, text);
1204}
1205
1207{
1208 Q_Q(QWidgetTextControl);
1209#ifndef QT_NO_SHORTCUT
1210 if (e == QKeySequence::SelectAll) {
1211 e->accept();
1212 q->selectAll();
1213#ifndef QT_NO_CLIPBOARD
1215#endif
1216 return;
1217 }
1218#ifndef QT_NO_CLIPBOARD
1219 else if (e == QKeySequence::Copy) {
1220 e->accept();
1221 q->copy();
1222 return;
1223 }
1224#endif
1225#endif // QT_NO_SHORTCUT
1226
1228 && cursorMoveKeyEvent(e))
1229 goto accept;
1230
1232 if ((e->key() == Qt::Key_Return
1233 || e->key() == Qt::Key_Enter
1234#ifdef QT_KEYPAD_NAVIGATION
1235 || e->key() == Qt::Key_Select
1236#endif
1237 )
1238 && cursor.hasSelection()) {
1239
1240 e->accept();
1242 return;
1243 }
1244 }
1245
1247 e->ignore();
1248 return;
1249 }
1250
1251 if (e->key() == Qt::Key_Direction_L || e->key() == Qt::Key_Direction_R) {
1255 goto accept;
1256 }
1257
1258 // schedule a repaint of the region of the cursor, as when we move it we
1259 // want to make sure the old cursor disappears (not noticeable when moving
1260 // only a few pixels but noticeable when jumping between cells in tables for
1261 // example)
1263
1265 QTextBlockFormat blockFmt = cursor.blockFormat();
1267 if (list && cursor.atBlockStart() && !cursor.hasSelection()) {
1268 list->remove(cursor.block());
1269 } else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
1270 blockFmt.setIndent(blockFmt.indent() - 1);
1271 cursor.setBlockFormat(blockFmt);
1272 } else {
1273 QTextCursor localCursor = cursor;
1274 localCursor.deletePreviousChar();
1275 if (cursor.d)
1276 cursor.d->setX();
1277 }
1278 goto accept;
1279 }
1280#ifndef QT_NO_SHORTCUT
1283 e->accept();
1284 goto accept;
1285 } else if (e == QKeySequence::InsertLineSeparator) {
1286 cursor.insertText(QString(QChar::LineSeparator));
1287 e->accept();
1288 goto accept;
1289 }
1290#endif
1291 if (false) {
1292 }
1293#ifndef QT_NO_SHORTCUT
1294 else if (e == QKeySequence::Undo) {
1295 q->undo();
1296 }
1297 else if (e == QKeySequence::Redo) {
1298 q->redo();
1299 }
1300#ifndef QT_NO_CLIPBOARD
1301 else if (e == QKeySequence::Cut) {
1302 q->cut();
1303 }
1304 else if (e == QKeySequence::Paste) {
1306 if (QGuiApplication::clipboard()->supportsSelection()) {
1307 if (e->modifiers() == (Qt::CTRL | Qt::SHIFT) && e->key() == Qt::Key_Insert)
1309 }
1310 q->paste(mode);
1311 }
1312#endif
1313 else if (e == QKeySequence::Delete) {
1314 QTextCursor localCursor = cursor;
1315 localCursor.deleteChar();
1316 if (cursor.d)
1317 cursor.d->setX();
1318 } else if (e == QKeySequence::Backspace) {
1319 QTextCursor localCursor = cursor;
1320 localCursor.deletePreviousChar();
1321 if (cursor.d)
1322 cursor.d->setX();
1323 }else if (e == QKeySequence::DeleteEndOfWord) {
1324 if (!cursor.hasSelection())
1327 }
1328 else if (e == QKeySequence::DeleteStartOfWord) {
1329 if (!cursor.hasSelection())
1332 }
1333 else if (e == QKeySequence::DeleteEndOfLine) {
1334 QTextBlock block = cursor.block();
1335 if (cursor.position() == block.position() + block.length() - 2)
1337 else
1340 }
1341#endif // QT_NO_SHORTCUT
1342 else {
1343 goto process;
1344 }
1345 goto accept;
1346
1347process:
1348 {
1349 if (q->isAcceptableInput(e)) {
1350 if (overwriteMode
1351 // no need to call deleteChar() if we have a selection, insertText
1352 // does it already
1353 && !cursor.hasSelection()
1354 && !cursor.atBlockEnd())
1356
1357 cursor.insertText(e->text());
1359 } else {
1360 e->ignore();
1361 return;
1362 }
1363 }
1364
1365 accept:
1366
1367#ifndef QT_NO_CLIPBOARD
1369#endif
1370
1371 e->accept();
1372 cursorOn = true;
1373
1374 q->ensureCursorVisible();
1375
1377}
1378
1380{
1381 Q_UNUSED(type);
1382 Q_UNUSED(name);
1383 return QVariant();
1384}
1385
1387{
1388 Q_Q(QWidgetTextControl);
1389 QRectF br = q->blockBoundingRect(block);
1390 br.setRight(qreal(INT_MAX)); // the block might have shrunk
1391 emit q->updateRequest(br);
1392}
1393
1395{
1396 Q_Q(const QWidgetTextControl);
1397 const QTextBlock block = doc->findBlock(position);
1398 if (!block.isValid())
1399 return QRectF();
1400 const QAbstractTextDocumentLayout *docLayout = doc->documentLayout();
1401 const QTextLayout *layout = block.layout();
1402 const QPointF layoutPos = q->blockBoundingRect(block).topLeft();
1403 int relativePos = position - block.position();
1404 if (preeditCursor != 0) {
1405 int preeditPos = layout->preeditAreaPosition();
1406 if (relativePos == preeditPos)
1407 relativePos += preeditCursor;
1408 else if (relativePos > preeditPos)
1409 relativePos += layout->preeditAreaText().size();
1410 }
1411 QTextLine line = layout->lineForTextPosition(relativePos);
1412
1413 int cursorWidth;
1414 {
1415 bool ok = false;
1416 cursorWidth = docLayout->property("cursorWidth").toInt(&ok);
1417 if (!ok)
1418 cursorWidth = 1;
1419 }
1420
1421 QRectF r;
1422
1423 if (line.isValid()) {
1424 qreal x = line.cursorToX(relativePos);
1425 qreal w = 0;
1426 if (overwriteMode) {
1427 if (relativePos < line.textLength() - line.textStart())
1428 w = line.cursorToX(relativePos + 1) - x;
1429 else
1430 w = QFontMetrics(block.layout()->font()).horizontalAdvance(u' '); // in sync with QTextLine::draw()
1431 }
1432 r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(),
1433 cursorWidth + w, line.height());
1434 } else {
1435 r = QRectF(layoutPos.x(), layoutPos.y(), cursorWidth, 10); // #### correct height
1436 }
1437
1438 return r;
1439}
1440
1441namespace {
1442struct QTextFrameComparator {
1443 bool operator()(QTextFrame *frame, int position) { return frame->firstPosition() < position; }
1444 bool operator()(int position, QTextFrame *frame) { return position < frame->firstPosition(); }
1445};
1446}
1447
1449{
1450 QRectF r;
1451 QTextFrame *frame = cursor.currentFrame();
1452 const QList<QTextFrame *> children = frame->childFrames();
1453
1454 const QList<QTextFrame *>::ConstIterator firstFrame = std::lower_bound(children.constBegin(), children.constEnd(),
1455 cursor.selectionStart(), QTextFrameComparator());
1456 const QList<QTextFrame *>::ConstIterator lastFrame = std::upper_bound(children.constBegin(), children.constEnd(),
1457 cursor.selectionEnd(), QTextFrameComparator());
1458 for (QList<QTextFrame *>::ConstIterator it = firstFrame; it != lastFrame; ++it) {
1459 if ((*it)->frameFormat().position() != QTextFrameFormat::InFlow)
1460 r |= frame->document()->documentLayout()->frameBoundingRect(*it);
1461 }
1462 return r;
1463}
1464
1466{
1467 Q_D(const QWidgetTextControl);
1468
1469 QRectF r = d->rectForPosition(cursor.selectionStart());
1470
1471 if (cursor.hasComplexSelection() && cursor.currentTable()) {
1472 QTextTable *table = cursor.currentTable();
1473
1474 r = d->doc->documentLayout()->frameBoundingRect(table);
1475 /*
1476 int firstRow, numRows, firstColumn, numColumns;
1477 cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
1478
1479 const QTextTableCell firstCell = table->cellAt(firstRow, firstColumn);
1480 const QTextTableCell lastCell = table->cellAt(firstRow + numRows - 1, firstColumn + numColumns - 1);
1481
1482 const QAbstractTextDocumentLayout * const layout = doc->documentLayout();
1483
1484 QRectF tableSelRect = layout->blockBoundingRect(firstCell.firstCursorPosition().block());
1485
1486 for (int col = firstColumn; col < firstColumn + numColumns; ++col) {
1487 const QTextTableCell cell = table->cellAt(firstRow, col);
1488 const qreal y = layout->blockBoundingRect(cell.firstCursorPosition().block()).top();
1489
1490 tableSelRect.setTop(qMin(tableSelRect.top(), y));
1491 }
1492
1493 for (int row = firstRow; row < firstRow + numRows; ++row) {
1494 const QTextTableCell cell = table->cellAt(row, firstColumn);
1495 const qreal x = layout->blockBoundingRect(cell.firstCursorPosition().block()).left();
1496
1497 tableSelRect.setLeft(qMin(tableSelRect.left(), x));
1498 }
1499
1500 for (int col = firstColumn; col < firstColumn + numColumns; ++col) {
1501 const QTextTableCell cell = table->cellAt(firstRow + numRows - 1, col);
1502 const qreal y = layout->blockBoundingRect(cell.lastCursorPosition().block()).bottom();
1503
1504 tableSelRect.setBottom(qMax(tableSelRect.bottom(), y));
1505 }
1506
1507 for (int row = firstRow; row < firstRow + numRows; ++row) {
1508 const QTextTableCell cell = table->cellAt(row, firstColumn + numColumns - 1);
1509 const qreal x = layout->blockBoundingRect(cell.lastCursorPosition().block()).right();
1510
1511 tableSelRect.setRight(qMax(tableSelRect.right(), x));
1512 }
1513
1514 r = tableSelRect.toRect();
1515 */
1516 } else if (cursor.hasSelection()) {
1517 const int position = cursor.selectionStart();
1518 const int anchor = cursor.selectionEnd();
1519 const QTextBlock posBlock = d->doc->findBlock(position);
1520 const QTextBlock anchorBlock = d->doc->findBlock(anchor);
1521 if (posBlock == anchorBlock && posBlock.isValid() && posBlock.layout()->lineCount()) {
1522 const QTextLine posLine = posBlock.layout()->lineForTextPosition(position - posBlock.position());
1523 const QTextLine anchorLine = anchorBlock.layout()->lineForTextPosition(anchor - anchorBlock.position());
1524
1525 const int firstLine = qMin(posLine.lineNumber(), anchorLine.lineNumber());
1526 const int lastLine = qMax(posLine.lineNumber(), anchorLine.lineNumber());
1527 const QTextLayout *layout = posBlock.layout();
1528 r = QRectF();
1529 for (int i = firstLine; i <= lastLine; ++i) {
1530 r |= layout->lineAt(i).rect();
1531 r |= layout->lineAt(i).naturalTextRect(); // might be bigger in the case of wrap not enabled
1532 }
1533 r.translate(blockBoundingRect(posBlock).topLeft());
1534 } else {
1535 QRectF anchorRect = d->rectForPosition(cursor.selectionEnd());
1536 r |= anchorRect;
1538 QRectF frameRect(d->doc->documentLayout()->frameBoundingRect(cursor.currentFrame()));
1539 r.setLeft(frameRect.left());
1540 r.setRight(frameRect.right());
1541 }
1542 if (r.isValid())
1543 r.adjust(-1, -1, 1, 1);
1544 }
1545
1546 return r;
1547}
1548
1550{
1551 Q_D(const QWidgetTextControl);
1552 return selectionRect(d->cursor);
1553}
1554
1556 Qt::MouseButtons buttons, const QPoint &globalPos)
1557{
1558 Q_Q(QWidgetTextControl);
1559
1560 mousePressPos = pos.toPoint();
1561
1562#if QT_CONFIG(draganddrop)
1563 mightStartDrag = false;
1564#endif
1565
1567 e, QEvent::MouseButtonPress, button, pos, modifiers, buttons, globalPos)) {
1568 return;
1569 }
1570
1572 anchorOnMousePress = q->anchorAt(pos);
1573
1575 cursorIsFocusIndicator = false;
1578 }
1579 }
1580 if (!(button & Qt::LeftButton) ||
1582 e->ignore();
1583 return;
1584 }
1585 bool wasValid = blockWithMarkerUnderMouse.isValid();
1586 blockWithMarkerUnderMouse = q->blockWithMarkerAt(pos);
1587 if (wasValid != blockWithMarkerUnderMouse.isValid())
1588 emit q->blockMarkerHovered(blockWithMarkerUnderMouse);
1589
1590
1591 cursorIsFocusIndicator = false;
1592 const QTextCursor oldSelection = cursor;
1593 const int oldCursorPos = cursor.position();
1594
1596
1597 commitPreedit();
1598
1600 && ((pos - trippleClickPoint).toPoint().manhattanLength() < QApplication::startDragDistance())) {
1601
1606
1609 emit q->blockMarkerHovered(blockWithMarkerUnderMouse);
1610
1612 } else {
1613 int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
1614 if (cursorPos == -1) {
1615 e->ignore();
1616 return;
1617 }
1618
1623 }
1624
1626 extendBlockwiseSelection(cursorPos);
1628 extendWordwiseSelection(cursorPos, pos.x());
1629 else if (!wordSelectionEnabled)
1631 } else {
1632
1633 if (dragEnabled
1634 && cursor.hasSelection()
1636 && cursorPos >= cursor.selectionStart()
1637 && cursorPos <= cursor.selectionEnd()
1638 && q->hitTest(pos, Qt::ExactHit) != -1) {
1639#if QT_CONFIG(draganddrop)
1640 mightStartDrag = true;
1641#endif
1642 return;
1643 }
1644
1645 setCursorPosition(cursorPos);
1646 }
1647 }
1648
1650 q->ensureCursorVisible();
1651 if (cursor.position() != oldCursorPos)
1652 emit q->cursorPositionChanged();
1654 } else {
1655 if (cursor.position() != oldCursorPos) {
1656 emit q->cursorPositionChanged();
1657 emit q->microFocusChanged();
1658 }
1660 }
1661 repaintOldAndNewSelection(oldSelection);
1663}
1664
1666 Qt::MouseButtons buttons, const QPoint &globalPos)
1667{
1668 Q_Q(QWidgetTextControl);
1669
1671 QString anchor = q->anchorAt(mousePos);
1672 if (anchor != highlightedAnchor) {
1673 highlightedAnchor = anchor;
1674 emit q->linkHovered(anchor);
1675 }
1676 }
1677
1678 if (buttons & Qt::LeftButton) {
1679 const bool editable = interactionFlags & Qt::TextEditable;
1680
1681 if (!(mousePressed
1682 || editable
1686 return;
1687
1688 const QTextCursor oldSelection = cursor;
1689 const int oldCursorPos = cursor.position();
1690
1691 if (mightStartDrag) {
1692 if ((mousePos.toPoint() - mousePressPos).manhattanLength() > QApplication::startDragDistance())
1693 startDrag();
1694 return;
1695 }
1696
1697 const qreal mouseX = qreal(mousePos.x());
1698
1699 int newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit);
1700
1701 if (isPreediting()) {
1702 // note: oldCursorPos not including preedit
1703 int selectionStartPos = q->hitTest(mousePressPos, Qt::FuzzyHit);
1704
1705 if (newCursorPos != selectionStartPos) {
1706 commitPreedit();
1707 // commit invalidates positions
1708 newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit);
1709 selectionStartPos = q->hitTest(mousePressPos, Qt::FuzzyHit);
1710 setCursorPosition(selectionStartPos);
1711 }
1712 }
1713
1714 if (newCursorPos == -1)
1715 return;
1716
1720 }
1721
1723 extendBlockwiseSelection(newCursorPos);
1725 extendWordwiseSelection(newCursorPos, mouseX);
1726 else if (mousePressed && !isPreediting())
1728
1730 // don't call ensureVisible for the visible cursor to avoid jumping
1731 // scrollbars. the autoscrolling ensures smooth scrolling if necessary.
1732 //q->ensureCursorVisible();
1733 if (cursor.position() != oldCursorPos)
1734 emit q->cursorPositionChanged();
1736#ifndef QT_NO_IM
1737 if (contextWidget)
1739#endif //QT_NO_IM
1740 } else {
1741 //emit q->visibilityRequest(QRectF(mousePos, QSizeF(1, 1)));
1742 if (cursor.position() != oldCursorPos) {
1743 emit q->cursorPositionChanged();
1744 emit q->microFocusChanged();
1745 }
1746 }
1747 selectionChanged(true);
1748 repaintOldAndNewSelection(oldSelection);
1749 } else {
1750 bool wasValid = blockWithMarkerUnderMouse.isValid();
1751 blockWithMarkerUnderMouse = q->blockWithMarkerAt(mousePos);
1752 if (wasValid != blockWithMarkerUnderMouse.isValid())
1753 emit q->blockMarkerHovered(blockWithMarkerUnderMouse);
1754 }
1755
1756 sendMouseEventToInputContext(e, QEvent::MouseMove, button, mousePos, modifiers, buttons, globalPos);
1757}
1758
1760 Qt::MouseButtons buttons, const QPoint &globalPos)
1761{
1762 Q_Q(QWidgetTextControl);
1763
1764 const QTextCursor oldSelection = cursor;
1766 e, QEvent::MouseButtonRelease, button, pos, modifiers, buttons, globalPos)) {
1767 repaintOldAndNewSelection(oldSelection);
1768 return;
1769 }
1770
1771 const int oldCursorPos = cursor.position();
1772
1773#if QT_CONFIG(draganddrop)
1775 mousePressed = false;
1779 }
1780#endif
1781 if (mousePressed) {
1782 mousePressed = false;
1783#ifndef QT_NO_CLIPBOARD
1785 selectionChanged(true);
1786 } else if (button == Qt::MiddleButton
1788 && QGuiApplication::clipboard()->supportsSelection()) {
1791 if (md)
1792 q->insertFromMimeData(md);
1793#endif
1794 }
1795
1796 repaintOldAndNewSelection(oldSelection);
1797
1798 if (cursor.position() != oldCursorPos) {
1799 emit q->cursorPositionChanged();
1800 emit q->microFocusChanged();
1801 }
1802
1803 // toggle any checkbox that the user clicks
1806 QTextBlock markerBlock = q->blockWithMarkerAt(pos);
1807 if (markerBlock == blockWithMarkerUnderMouse) {
1809 switch (fmt.marker()) {
1812 break;
1815 break;
1816 default:
1817 break;
1818 }
1820 }
1821 }
1822
1824
1825 // Ignore event unless left button has been pressed
1826 if (!(button & Qt::LeftButton)) {
1827 e->ignore();
1828 return;
1829 }
1830
1831 const QString anchor = q->anchorAt(pos);
1832
1833 // Ignore event without selection anchor
1834 if (anchor.isEmpty()) {
1835 e->ignore();
1836 return;
1837 }
1838
1839 if (!cursor.hasSelection()
1840 || (anchor == anchorOnMousePress && hadSelectionOnMousePress)) {
1841
1842 const int anchorPos = q->hitTest(pos, Qt::ExactHit);
1843
1844 // Ignore event without valid anchor position
1845 if (anchorPos < 0) {
1846 e->ignore();
1847 return;
1848 }
1849
1850 cursor.setPosition(anchorPos);
1851 QString anchor = anchorOnMousePress;
1854 }
1855 }
1856}
1857
1859 Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons,
1860 const QPoint &globalPos)
1861{
1862 Q_Q(QWidgetTextControl);
1863
1864 if (button == Qt::LeftButton
1866
1867#if QT_CONFIG(draganddrop)
1868 mightStartDrag = false;
1869#endif
1870 commitPreedit();
1871
1872 const QTextCursor oldSelection = cursor;
1875 bool doEmit = false;
1876 if (line.isValid() && line.textLength()) {
1878 doEmit = true;
1879 }
1880 repaintOldAndNewSelection(oldSelection);
1881
1882 cursorIsFocusIndicator = false;
1884
1887 if (doEmit) {
1889#ifndef QT_NO_CLIPBOARD
1891#endif
1892 emit q->cursorPositionChanged();
1893 }
1895 modifiers, buttons, globalPos)) {
1896 e->ignore();
1897 }
1898}
1899
1901 QEvent *e, QEvent::Type eventType, Qt::MouseButton button, const QPointF &pos,
1902 Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos)
1903{
1904 Q_UNUSED(eventType);
1906 Q_UNUSED(pos);
1908 Q_UNUSED(buttons);
1909 Q_UNUSED(globalPos);
1910#if !defined(QT_NO_IM)
1911 Q_Q(QWidgetTextControl);
1912
1913 if (isPreediting()) {
1915 int cursorPos = q->hitTest(pos, Qt::FuzzyHit) - cursor.position();
1916
1917 if (cursorPos < 0 || cursorPos > layout->preeditAreaText().size())
1918 cursorPos = -1;
1919
1920 if (cursorPos >= 0) {
1921 if (eventType == QEvent::MouseButtonRelease)
1922 QGuiApplication::inputMethod()->invokeAction(QInputMethod::Click, cursorPos);
1923
1924 e->setAccepted(true);
1925 return true;
1926 }
1927 }
1928#else
1929 Q_UNUSED(e);
1930#endif
1931 return false;
1932}
1933
1934void QWidgetTextControlPrivate::contextMenuEvent(const QPoint &screenPos, const QPointF &docPos, QWidget *contextWidget)
1935{
1936#ifdef QT_NO_CONTEXTMENU
1937 Q_UNUSED(screenPos);
1938 Q_UNUSED(docPos);
1940#else
1941 Q_Q(QWidgetTextControl);
1942 QMenu *menu = q->createStandardContextMenu(docPos, contextWidget);
1943 if (!menu)
1944 return;
1946
1947 if (auto *widget = qobject_cast<QWidget *>(parent)) {
1948 if (auto *window = widget->window()->windowHandle())
1949 QMenuPrivate::get(menu)->topData()->initialScreen = window->screen();
1950 }
1951
1952 menu->popup(screenPos);
1953#endif
1954}
1955
1957{
1958 Q_Q(QWidgetTextControl);
1959 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
1960 e->ignore();
1961 return false;
1962 }
1963
1965
1966 return true; // accept proposed action
1967}
1968
1970{
1971 Q_Q(QWidgetTextControl);
1972
1973 const QRectF crect = q->cursorRect(dndFeedbackCursor);
1975
1976 if (crect.isValid())
1977 emit q->updateRequest(crect);
1978}
1979
1981{
1982 Q_Q(QWidgetTextControl);
1983 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
1984 e->ignore();
1985 return false;
1986 }
1987
1988 const int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
1989 if (cursorPos != -1) {
1990 QRectF crect = q->cursorRect(dndFeedbackCursor);
1991 if (crect.isValid())
1992 emit q->updateRequest(crect);
1993
1995 dndFeedbackCursor.setPosition(cursorPos);
1996
1997 crect = q->cursorRect(dndFeedbackCursor);
1998 emit q->updateRequest(crect);
1999 }
2000
2001 return true; // accept proposed action
2002}
2003
2005{
2006 Q_Q(QWidgetTextControl);
2008
2009 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData))
2010 return false;
2011
2013
2014 QTextCursor insertionCursor = q->cursorForPosition(pos);
2015 insertionCursor.beginEditBlock();
2016
2017 if (dropAction == Qt::MoveAction && source == contextWidget)
2019
2020 cursor = insertionCursor;
2021 q->insertFromMimeData(mimeData);
2022 insertionCursor.endEditBlock();
2023 q->ensureCursorVisible();
2024 return true; // accept proposed action
2025}
2026
2028{
2029 Q_Q(QWidgetTextControl);
2031 e->ignore();
2032 return;
2033 }
2034 bool isGettingInput = !e->commitString().isEmpty()
2036 || e->replacementLength() > 0;
2037
2038 if (!isGettingInput && e->attributes().isEmpty()) {
2039 e->ignore();
2040 return;
2041 }
2042
2043 int oldCursorPos = cursor.position();
2044
2046 if (isGettingInput) {
2048 }
2049
2050 QTextBlock block;
2051
2052 // insert commit string
2053 if (!e->commitString().isEmpty() || e->replacementLength()) {
2054 if (e->commitString().endsWith(QChar::LineFeed))
2055 block = cursor.block(); // Remember the block where the preedit text is
2057 c.setPosition(c.position() + e->replacementStart());
2058 c.setPosition(c.position() + e->replacementLength(), QTextCursor::KeepAnchor);
2059 c.insertText(e->commitString());
2060 }
2061
2062 for (int i = 0; i < e->attributes().size(); ++i) {
2063 const QInputMethodEvent::Attribute &a = e->attributes().at(i);
2064 if (a.type == QInputMethodEvent::Selection) {
2065 QTextCursor oldCursor = cursor;
2066 int blockStart = a.start + cursor.block().position();
2068 cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor);
2069 q->ensureCursorVisible();
2070 repaintOldAndNewSelection(oldCursor);
2071 }
2072 }
2073
2074 if (!block.isValid())
2075 block = cursor.block();
2076 QTextLayout *layout = block.layout();
2077 if (isGettingInput)
2078 layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
2079 QList<QTextLayout::FormatRange> overrides;
2080 overrides.reserve(e->attributes().size());
2081 const int oldPreeditCursor = preeditCursor;
2083 hideCursor = false;
2084 for (int i = 0; i < e->attributes().size(); ++i) {
2085 const QInputMethodEvent::Attribute &a = e->attributes().at(i);
2086 if (a.type == QInputMethodEvent::Cursor) {
2087 preeditCursor = a.start;
2088 hideCursor = !a.length;
2089 } else if (a.type == QInputMethodEvent::TextFormat) {
2091 f.merge(qvariant_cast<QTextFormat>(a.value).toCharFormat());
2092 if (f.isValid()) {
2094 o.start = a.start + cursor.position() - block.position();
2095 o.length = a.length;
2096 o.format = f;
2097
2098 // Make sure list is sorted by start index
2100 while (it != overrides.begin()) {
2102 if (o.start >= previous->start) {
2103 overrides.insert(it, o);
2104 break;
2105 }
2106 it = previous;
2107 }
2108
2109 if (it == overrides.begin())
2110 overrides.prepend(o);
2111 }
2112 }
2113 }
2114
2115 if (cursor.charFormat().isValid()) {
2116 int start = cursor.position() - block.position();
2117 int end = start + e->preeditString().size();
2118
2120 while (it != overrides.end()) {
2122 int rangeStart = range.start;
2123 if (rangeStart > start) {
2125 o.start = start;
2126 o.length = rangeStart - start;
2127 o.format = cursor.charFormat();
2128 it = overrides.insert(it, o) + 1;
2129 }
2130
2131 ++it;
2132 start = range.start + range.length;
2133 }
2134
2135 if (start < end) {
2137 o.start = start;
2138 o.length = end - start;
2139 o.format = cursor.charFormat();
2140 overrides.append(o);
2141 }
2142 }
2143 layout->setFormats(overrides);
2144
2146
2147 if (cursor.d)
2148 cursor.d->setX();
2149 if (oldCursorPos != cursor.position())
2150 emit q->cursorPositionChanged();
2151 if (oldPreeditCursor != preeditCursor)
2152 emit q->microFocusChanged();
2153}
2154
2156{
2157 Q_D(const QWidgetTextControl);
2158 QTextBlock block = d->cursor.block();
2159 switch(property) {
2161 return cursorRect();
2163 return d->rectForPosition(d->cursor.anchor());
2164 case Qt::ImFont:
2165 return QVariant(d->cursor.charFormat().font());
2166 case Qt::ImCursorPosition: {
2167 const QPointF pt = argument.toPointF();
2168 if (!pt.isNull())
2169 return QVariant(cursorForPosition(pt).position() - block.position());
2170 return QVariant(d->cursor.position() - block.position()); }
2172 return QVariant(block.text());
2174 return QVariant(d->cursor.selectedText());
2176 return QVariant(); // No limit.
2178 return QVariant(d->cursor.anchor() - block.position());
2180 const QPointF pt = argument.toPointF();
2181 if (!pt.isNull())
2182 return QVariant(cursorForPosition(pt).position());
2183 return QVariant(d->cursor.position()); }
2185 {
2186 int maxLength = argument.isValid() ? argument.toInt() : 1024;
2187 QTextCursor tmpCursor = d->cursor;
2188 int localPos = d->cursor.position() - block.position();
2189 QString result = block.text().mid(localPos);
2190 while (result.size() < maxLength) {
2191 int currentBlock = tmpCursor.blockNumber();
2192 tmpCursor.movePosition(QTextCursor::NextBlock);
2193 if (tmpCursor.blockNumber() == currentBlock)
2194 break;
2195 result += u'\n' + tmpCursor.block().text();
2196 }
2197 return QVariant(result);
2198 }
2200 {
2201 int maxLength = argument.isValid() ? argument.toInt() : 1024;
2202 QTextCursor tmpCursor = d->cursor;
2203 int localPos = d->cursor.position() - block.position();
2204 int numBlocks = 0;
2205 int resultLen = localPos;
2206 while (resultLen < maxLength) {
2207 int currentBlock = tmpCursor.blockNumber();
2208 tmpCursor.movePosition(QTextCursor::PreviousBlock);
2209 if (tmpCursor.blockNumber() == currentBlock)
2210 break;
2211 numBlocks++;
2212 resultLen += tmpCursor.block().length();
2213 }
2215 while (numBlocks) {
2216 result += tmpCursor.block().text() + u'\n';
2217 tmpCursor.movePosition(QTextCursor::NextBlock);
2218 --numBlocks;
2219 }
2220 result += QStringView{block.text()}.mid(0, localPos);
2221 return QVariant(result);
2222 }
2223 default:
2224 return QVariant();
2225 }
2226}
2227
2229{
2231 reason);
2232 processEvent(&ev);
2233}
2234
2236{
2237 Q_Q(QWidgetTextControl);
2238 emit q->updateRequest(q->selectionRect());
2239 if (e->gotFocus()) {
2240#ifdef QT_KEYPAD_NAVIGATION
2241 if (!QApplicationPrivate::keypadNavigationEnabled() || (hasEditFocus && (e->reason() == Qt::PopupFocusReason))) {
2242#endif
2245 setCursorVisible(true);
2246 }
2247#ifdef QT_KEYPAD_NAVIGATION
2248 }
2249#endif
2250 } else {
2251 setCursorVisible(false);
2252 cursorOn = false;
2253
2256 && e->reason() != Qt::PopupFocusReason
2257 && cursor.hasSelection()) {
2259 }
2260 }
2261 hasFocus = e->gotFocus();
2262}
2263
2265{
2266 if (anchorCursor.hasSelection()) {
2267 QTextCursor cursor = anchorCursor;
2272 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref))
2274 }
2275 return QString();
2276}
2277
2278#ifdef QT_KEYPAD_NAVIGATION
2279void QWidgetTextControlPrivate::editFocusEvent(QEvent *e)
2280{
2281 Q_Q(QWidgetTextControl);
2282
2283 if (QApplicationPrivate::keypadNavigationEnabled()) {
2284 if (e->type() == QEvent::EnterEditFocus && interactionFlags & Qt::TextEditable) {
2285 const QTextCursor oldSelection = cursor;
2286 const int oldCursorPos = cursor.position();
2288 q->ensureCursorVisible();
2289 if (moved) {
2290 if (cursor.position() != oldCursorPos)
2291 emit q->cursorPositionChanged();
2292 emit q->microFocusChanged();
2293 }
2295 repaintOldAndNewSelection(oldSelection);
2296
2298 } else
2300 }
2301
2302 hasEditFocus = e->type() == QEvent::EnterEditFocus;
2303}
2304#endif
2305
2306#ifndef QT_NO_CONTEXTMENU
2307void setActionIcon(QAction *action, const QString &name)
2308{
2310 if (!icon.isNull())
2311 action->setIcon(icon);
2312}
2313
2315{
2316 Q_D(QWidgetTextControl);
2317
2318 const bool showTextSelectionActions = d->interactionFlags & (Qt::TextEditable | Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
2319
2320 d->linkToCopy = QString();
2321 if (!pos.isNull())
2322 d->linkToCopy = anchorAt(pos);
2323
2324 if (d->linkToCopy.isEmpty() && !showTextSelectionActions)
2325 return nullptr;
2326
2327 QMenu *menu = new QMenu(parent);
2328 QAction *a;
2329
2330 if (d->interactionFlags & Qt::TextEditable) {
2331 a = menu->addAction(tr("&Undo") + ACCEL_KEY(QKeySequence::Undo), this, SLOT(undo()));
2332 a->setEnabled(d->doc->isUndoAvailable());
2333 a->setObjectName(QStringLiteral("edit-undo"));
2334 setActionIcon(a, QStringLiteral("edit-undo"));
2335 a = menu->addAction(tr("&Redo") + ACCEL_KEY(QKeySequence::Redo), this, SLOT(redo()));
2336 a->setEnabled(d->doc->isRedoAvailable());
2337 a->setObjectName(QStringLiteral("edit-redo"));
2338 setActionIcon(a, QStringLiteral("edit-redo"));
2339 menu->addSeparator();
2340
2341#ifndef QT_NO_CLIPBOARD
2342 a = menu->addAction(tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut), this, SLOT(cut()));
2343 a->setEnabled(d->cursor.hasSelection());
2344 a->setObjectName(QStringLiteral("edit-cut"));
2345 setActionIcon(a, QStringLiteral("edit-cut"));
2346#endif
2347 }
2348
2349#ifndef QT_NO_CLIPBOARD
2350 if (showTextSelectionActions) {
2351 a = menu->addAction(tr("&Copy") + ACCEL_KEY(QKeySequence::Copy), this, SLOT(copy()));
2352 a->setEnabled(d->cursor.hasSelection());
2353 a->setObjectName(QStringLiteral("edit-copy"));
2354 setActionIcon(a, QStringLiteral("edit-copy"));
2355 }
2356
2357 if ((d->interactionFlags & Qt::LinksAccessibleByKeyboard)
2358 || (d->interactionFlags & Qt::LinksAccessibleByMouse)) {
2359
2360 a = menu->addAction(tr("Copy &Link Location"), this, SLOT(_q_copyLink()));
2361 a->setEnabled(!d->linkToCopy.isEmpty());
2362 a->setObjectName(QStringLiteral("link-copy"));
2363 }
2364#endif // QT_NO_CLIPBOARD
2365
2366 if (d->interactionFlags & Qt::TextEditable) {
2367#ifndef QT_NO_CLIPBOARD
2368 a = menu->addAction(tr("&Paste") + ACCEL_KEY(QKeySequence::Paste), this, SLOT(paste()));
2369 a->setEnabled(canPaste());
2370 a->setObjectName(QStringLiteral("edit-paste"));
2371 setActionIcon(a, QStringLiteral("edit-paste"));
2372#endif
2373 a = menu->addAction(tr("Delete"), this, SLOT(_q_deleteSelected()));
2374 a->setEnabled(d->cursor.hasSelection());
2375 a->setObjectName(QStringLiteral("edit-delete"));
2376 setActionIcon(a, QStringLiteral("edit-delete"));
2377 }
2378
2379
2380 if (showTextSelectionActions) {
2381 menu->addSeparator();
2382 a = menu->addAction(tr("Select All") + ACCEL_KEY(QKeySequence::SelectAll), this, SLOT(selectAll()));
2383 a->setEnabled(!d->doc->isEmpty());
2384 a->setObjectName(QStringLiteral("select-all"));
2385 setActionIcon(a, QStringLiteral("edit-select-all"));
2386 }
2387
2388 if ((d->interactionFlags & Qt::TextEditable) && QGuiApplication::styleHints()->useRtlExtensions()) {
2389 menu->addSeparator();
2390 QUnicodeControlCharacterMenu *ctrlCharacterMenu = new QUnicodeControlCharacterMenu(this, menu);
2391 menu->addMenu(ctrlCharacterMenu);
2392 }
2393
2394 return menu;
2395}
2396#endif // QT_NO_CONTEXTMENU
2397
2399{
2400 Q_D(const QWidgetTextControl);
2401 int cursorPos = hitTest(pos, Qt::FuzzyHit);
2402 if (cursorPos == -1)
2403 cursorPos = 0;
2404 QTextCursor c(d->doc);
2405 c.setPosition(cursorPos);
2406 return c;
2407}
2408
2410{
2411 Q_D(const QWidgetTextControl);
2412 if (cursor.isNull())
2413 return QRectF();
2414
2415 return d->rectForPosition(cursor.position());
2416}
2417
2419{
2420 Q_D(const QWidgetTextControl);
2421 return cursorRect(d->cursor);
2422}
2423
2425{
2426 if (cursor.isNull())
2427 return QRectF();
2428
2429 return rectForPosition(cursor.position()).adjusted(-4, 0, 4, 0);
2430}
2431
2433{
2434 Q_D(const QWidgetTextControl);
2435 return d->doc->documentLayout()->anchorAt(pos);
2436}
2437
2439{
2440 Q_D(const QWidgetTextControl);
2441
2442 return d->anchorForCursor(d->cursor);
2443}
2444
2446{
2447 Q_D(const QWidgetTextControl);
2448 return d->doc->documentLayout()->blockWithMarkerAt(pos);
2449}
2450
2452{
2453 Q_D(const QWidgetTextControl);
2454 return d->overwriteMode;
2455}
2456
2458{
2459 Q_D(QWidgetTextControl);
2460 d->overwriteMode = overwrite;
2461}
2462
2464{
2465 Q_D(const QWidgetTextControl);
2466 return d->doc->documentLayout()->property("cursorWidth").toInt();
2467}
2468
2470{
2471 Q_D(QWidgetTextControl);
2472 if (width == -1)
2473 width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth, nullptr, qobject_cast<QWidget *>(parent()));
2474 d->doc->documentLayout()->setProperty("cursorWidth", width);
2475 d->repaintCursor();
2476}
2477
2479{
2480 Q_D(const QWidgetTextControl);
2481 return d->acceptRichText;
2482}
2483
2485{
2486 Q_D(QWidgetTextControl);
2487 d->acceptRichText = accept;
2488}
2489
2490#if QT_CONFIG(textedit)
2491
2492void QWidgetTextControl::setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)
2493{
2494 Q_D(QWidgetTextControl);
2495
2496 QMultiHash<int, int> hash;
2497 for (int i = 0; i < d->extraSelections.size(); ++i) {
2498 const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(i);
2499 hash.insert(esel.cursor.anchor(), i);
2500 }
2501
2502 for (int i = 0; i < selections.size(); ++i) {
2503 const QTextEdit::ExtraSelection &sel = selections.at(i);
2504 const auto it = hash.constFind(sel.cursor.anchor());
2505 if (it != hash.cend()) {
2506 const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(it.value());
2507 if (esel.cursor.position() == sel.cursor.position()
2508 && esel.format == sel.format) {
2509 hash.erase(it);
2510 continue;
2511 }
2512 }
2513 QRectF r = selectionRect(sel.cursor);
2514 if (sel.format.boolProperty(QTextFormat::FullWidthSelection)) {
2515 r.setLeft(0);
2516 r.setWidth(qreal(INT_MAX));
2517 }
2519 }
2520
2521 for (auto it = hash.cbegin(); it != hash.cend(); ++it) {
2522 const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(it.value());
2523 QRectF r = selectionRect(esel.cursor);
2524 if (esel.format.boolProperty(QTextFormat::FullWidthSelection)) {
2525 r.setLeft(0);
2526 r.setWidth(qreal(INT_MAX));
2527 }
2529 }
2530
2531 d->extraSelections.resize(selections.size());
2532 for (int i = 0; i < selections.size(); ++i) {
2533 d->extraSelections[i].cursor = selections.at(i).cursor;
2534 d->extraSelections[i].format = selections.at(i).format;
2535 }
2536}
2537
2538QList<QTextEdit::ExtraSelection> QWidgetTextControl::extraSelections() const
2539{
2540 Q_D(const QWidgetTextControl);
2541 QList<QTextEdit::ExtraSelection> selections;
2542 const int numExtraSelections = d->extraSelections.size();
2543 selections.reserve(numExtraSelections);
2544 for (int i = 0; i < numExtraSelections; ++i) {
2546 const QAbstractTextDocumentLayout::Selection &sel2 = d->extraSelections.at(i);
2547 sel.cursor = sel2.cursor;
2548 sel.format = sel2.format;
2549 selections.append(sel);
2550 }
2551 return selections;
2552}
2553
2554#endif // QT_CONFIG(textedit)
2555
2557{
2558 Q_D(QWidgetTextControl);
2559 d->doc->setTextWidth(width);
2560}
2561
2563{
2564 Q_D(const QWidgetTextControl);
2565 return d->doc->textWidth();
2566}
2567
2569{
2570 Q_D(const QWidgetTextControl);
2571 return d->doc->size();
2572}
2573
2575{
2576 Q_D(QWidgetTextControl);
2577 d->openExternalLinks = open;
2578}
2579
2581{
2582 Q_D(const QWidgetTextControl);
2583 return d->openExternalLinks;
2584}
2585
2587{
2588 Q_D(const QWidgetTextControl);
2589 return d->ignoreUnusedNavigationEvents;
2590}
2591
2593{
2594 Q_D(QWidgetTextControl);
2595 d->ignoreUnusedNavigationEvents = ignore;
2596}
2597
2599{
2600 Q_D(QWidgetTextControl);
2601 const QTextCursor oldSelection = d->cursor;
2602 const bool moved = d->cursor.movePosition(op, mode);
2603 d->_q_updateCurrentCharFormatAndSelection();
2605 d->repaintOldAndNewSelection(oldSelection);
2606 if (moved)
2608}
2609
2611{
2612#ifndef QT_NO_CLIPBOARD
2613 Q_D(const QWidgetTextControl);
2614 if (d->interactionFlags & Qt::TextEditable) {
2615 const QMimeData *md = QGuiApplication::clipboard()->mimeData();
2616 return md && canInsertFromMimeData(md);
2617 }
2618#endif
2619 return false;
2620}
2621
2623{
2624 Q_D(QWidgetTextControl);
2625 d->cursorIsFocusIndicator = b;
2626 d->repaintCursor();
2627}
2628
2630{
2631 Q_D(const QWidgetTextControl);
2632 return d->cursorIsFocusIndicator;
2633}
2634
2635
2637{
2638 Q_D(QWidgetTextControl);
2639 d->dragEnabled = enabled;
2640}
2641
2643{
2644 Q_D(const QWidgetTextControl);
2645 return d->dragEnabled;
2646}
2647
2649{
2650 Q_D(QWidgetTextControl);
2651 d->wordSelectionEnabled = enabled;
2652}
2653
2655{
2656 Q_D(const QWidgetTextControl);
2657 return d->wordSelectionEnabled;
2658}
2659
2661{
2662 return d_func()->isPreediting();
2663}
2664
2665#ifndef QT_NO_PRINTER
2667{
2668 Q_D(const QWidgetTextControl);
2669 if (!printer)
2670 return;
2671 QTextDocument *tempDoc = nullptr;
2672 const QTextDocument *doc = d->doc;
2673 if (QPagedPaintDevicePrivate::get(printer)->printSelectionOnly) {
2674 if (!d->cursor.hasSelection())
2675 return;
2676 tempDoc = new QTextDocument(const_cast<QTextDocument *>(doc));
2677 tempDoc->setResourceProvider(doc->resourceProvider());
2679 tempDoc->setPageSize(doc->pageSize());
2680 tempDoc->setDefaultFont(doc->defaultFont());
2681 tempDoc->setUseDesignMetrics(doc->useDesignMetrics());
2682 QTextCursor(tempDoc).insertFragment(d->cursor.selection());
2683 doc = tempDoc;
2684
2685 // copy the custom object handlers
2686 doc->documentLayout()->d_func()->handlers = d->doc->documentLayout()->d_func()->handlers;
2687 }
2688 doc->print(printer);
2689 delete tempDoc;
2690}
2691#endif
2692
2694{
2695 Q_D(const QWidgetTextControl);
2696 const QTextDocumentFragment fragment(d->cursor);
2697 return new QTextEditMimeData(fragment);
2698}
2699
2701{
2702 Q_D(const QWidgetTextControl);
2703 if (d->acceptRichText)
2704 return (source->hasText() && !source->text().isEmpty())
2705 || source->hasHtml()
2706 || source->hasFormat("application/x-qrichtext"_L1)
2707 || source->hasFormat("application/x-qt-richtext"_L1);
2708 else
2709 return source->hasText() && !source->text().isEmpty();
2710}
2711
2713{
2714 Q_D(QWidgetTextControl);
2715 if (!(d->interactionFlags & Qt::TextEditable) || !source)
2716 return;
2717
2718 bool hasData = false;
2719 QTextDocumentFragment fragment;
2720#if QT_CONFIG(textmarkdownreader)
2721 const auto formats = source->formats();
2722 if (formats.size() && formats.first() == "text/markdown"_L1) {
2723 auto s = QString::fromUtf8(source->data("text/markdown"_L1));
2724 fragment = QTextDocumentFragment::fromMarkdown(s);
2725 hasData = true;
2726 } else
2727#endif
2728#ifndef QT_NO_TEXTHTMLPARSER
2729 if (source->hasFormat("application/x-qrichtext"_L1) && d->acceptRichText) {
2730 // x-qrichtext is always UTF-8 (taken from Qt3 since we don't use it anymore).
2731 const QString richtext = "<meta name=\"qrichtext\" content=\"1\" />"_L1
2732 + QString::fromUtf8(source->data("application/x-qrichtext"_L1));
2733 fragment = QTextDocumentFragment::fromHtml(richtext, d->doc);
2734 hasData = true;
2735 } else if (source->hasHtml() && d->acceptRichText) {
2736 fragment = QTextDocumentFragment::fromHtml(source->html(), d->doc);
2737 hasData = true;
2738 }
2739#endif // QT_NO_TEXTHTMLPARSER
2740 if (!hasData) {
2741 const QString text = source->text();
2742 if (!text.isNull()) {
2744 hasData = true;
2745 }
2746 }
2747
2748 if (hasData)
2749 d->cursor.insertFragment(fragment);
2751}
2752
2753bool QWidgetTextControl::findNextPrevAnchor(const QTextCursor &startCursor, bool next, QTextCursor &newAnchor)
2754{
2755 Q_D(QWidgetTextControl);
2756
2757 int anchorStart = -1;
2758 QString anchorHref;
2759 int anchorEnd = -1;
2760
2761 if (next) {
2762 const int startPos = startCursor.selectionEnd();
2763
2764 QTextBlock block = d->doc->findBlock(startPos);
2765 QTextBlock::Iterator it = block.begin();
2766
2767 while (!it.atEnd() && it.fragment().position() < startPos)
2768 ++it;
2769
2770 while (block.isValid()) {
2771 anchorStart = -1;
2772
2773 // find next anchor
2774 for (; !it.atEnd(); ++it) {
2775 const QTextFragment fragment = it.fragment();
2776 const QTextCharFormat fmt = fragment.charFormat();
2777
2778 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
2779 anchorStart = fragment.position();
2780 anchorHref = fmt.anchorHref();
2781 break;
2782 }
2783 }
2784
2785 if (anchorStart != -1) {
2786 anchorEnd = -1;
2787
2788 // find next non-anchor fragment
2789 for (; !it.atEnd(); ++it) {
2790 const QTextFragment fragment = it.fragment();
2791 const QTextCharFormat fmt = fragment.charFormat();
2792
2793 if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
2794 anchorEnd = fragment.position();
2795 break;
2796 }
2797 }
2798
2799 if (anchorEnd == -1)
2800 anchorEnd = block.position() + block.length() - 1;
2801
2802 // make found selection
2803 break;
2804 }
2805
2806 block = block.next();
2807 it = block.begin();
2808 }
2809 } else {
2810 int startPos = startCursor.selectionStart();
2811 if (startPos > 0)
2812 --startPos;
2813
2814 QTextBlock block = d->doc->findBlock(startPos);
2815 QTextBlock::Iterator blockStart = block.begin();
2816 QTextBlock::Iterator it = block.end();
2817
2818 if (startPos == block.position()) {
2819 it = block.begin();
2820 } else {
2821 do {
2822 if (it == blockStart) {
2824 block = QTextBlock();
2825 } else {
2826 --it;
2827 }
2828 } while (!it.atEnd() && it.fragment().position() + it.fragment().length() - 1 > startPos);
2829 }
2830
2831 while (block.isValid()) {
2832 anchorStart = -1;
2833
2834 if (!it.atEnd()) {
2835 do {
2836 const QTextFragment fragment = it.fragment();
2837 const QTextCharFormat fmt = fragment.charFormat();
2838
2839 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
2840 anchorStart = fragment.position() + fragment.length();
2841 anchorHref = fmt.anchorHref();
2842 break;
2843 }
2844
2845 if (it == blockStart)
2847 else
2848 --it;
2849 } while (!it.atEnd());
2850 }
2851
2852 if (anchorStart != -1 && !it.atEnd()) {
2853 anchorEnd = -1;
2854
2855 do {
2856 const QTextFragment fragment = it.fragment();
2857 const QTextCharFormat fmt = fragment.charFormat();
2858
2859 if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
2860 anchorEnd = fragment.position() + fragment.length();
2861 break;
2862 }
2863
2864 if (it == blockStart)
2866 else
2867 --it;
2868 } while (!it.atEnd());
2869
2870 if (anchorEnd == -1)
2871 anchorEnd = qMax(0, block.position());
2872
2873 break;
2874 }
2875
2876 block = block.previous();
2877 it = block.end();
2878 if (it != block.begin())
2879 --it;
2880 blockStart = block.begin();
2881 }
2882
2883 }
2884
2885 if (anchorStart != -1 && anchorEnd != -1) {
2886 newAnchor = d->cursor;
2887 newAnchor.setPosition(anchorStart);
2888 newAnchor.setPosition(anchorEnd, QTextCursor::KeepAnchor);
2889 return true;
2890 }
2891
2892 return false;
2893}
2894
2896{
2897 QTextCursor oldCursor = cursor;
2898
2899 if (href.isEmpty()) {
2900 QTextCursor tmp = cursor;
2901 if (tmp.selectionStart() != tmp.position())
2902 tmp.setPosition(tmp.selectionStart());
2904 href = tmp.charFormat().anchorHref();
2905 }
2906 if (href.isEmpty())
2907 return;
2908
2909 if (!cursor.hasSelection()) {
2910 QTextBlock block = cursor.block();
2911 const int cursorPos = cursor.position();
2912
2913 QTextBlock::Iterator it = block.begin();
2914 QTextBlock::Iterator linkFragment;
2915
2916 for (; !it.atEnd(); ++it) {
2917 QTextFragment fragment = it.fragment();
2918 const int fragmentPos = fragment.position();
2919 if (fragmentPos <= cursorPos &&
2920 fragmentPos + fragment.length() > cursorPos) {
2921 linkFragment = it;
2922 break;
2923 }
2924 }
2925
2926 if (!linkFragment.atEnd()) {
2927 it = linkFragment;
2928 cursor.setPosition(it.fragment().position());
2929 if (it != block.begin()) {
2930 do {
2931 --it;
2932 QTextFragment fragment = it.fragment();
2933 if (fragment.charFormat().anchorHref() != href)
2934 break;
2935 cursor.setPosition(fragment.position());
2936 } while (it != block.begin());
2937 }
2938
2939 for (it = linkFragment; !it.atEnd(); ++it) {
2940 QTextFragment fragment = it.fragment();
2941 if (fragment.charFormat().anchorHref() != href)
2942 break;
2943 cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
2944 }
2945 }
2946 }
2947
2948 if (hasFocus) {
2950 } else {
2951 cursorIsFocusIndicator = false;
2953 }
2954 repaintOldAndNewSelection(oldCursor);
2955
2956#ifndef QT_NO_DESKTOPSERVICES
2959 else
2960#endif
2961 emit q_func()->linkActivated(href);
2962}
2963
2964#if QT_CONFIG(tooltip)
2965void QWidgetTextControlPrivate::showToolTip(const QPoint &globalPos, const QPointF &pos, QWidget *contextWidget)
2966{
2967 const QString toolTip = q_func()->cursorForPosition(pos).charFormat().toolTip();
2968 if (toolTip.isEmpty())
2969 return;
2970 QToolTip::showText(globalPos, toolTip, contextWidget);
2971}
2972#endif // QT_CONFIG(tooltip)
2973
2975{
2977 if (layout && !layout->preeditAreaText().isEmpty())
2978 return true;
2979
2980 return false;
2981}
2982
2984{
2985 if (!isPreediting())
2986 return;
2987
2988 QGuiApplication::inputMethod()->commit();
2989
2990 if (!isPreediting())
2991 return;
2992
2994 preeditCursor = 0;
2995 QTextBlock block = cursor.block();
2996 QTextLayout *layout = block.layout();
2997 layout->setPreeditArea(-1, QString());
2998 layout->clearFormats();
3000}
3001
3003{
3004 Q_D(QWidgetTextControl);
3005
3006 if (!(d->interactionFlags & Qt::LinksAccessibleByKeyboard))
3007 return false;
3008
3009 QRectF crect = selectionRect();
3010 emit updateRequest(crect);
3011
3012 // If we don't have a current anchor, we start from the start/end
3013 if (!d->cursor.hasSelection()) {
3014 d->cursor = QTextCursor(d->doc);
3015 if (next)
3016 d->cursor.movePosition(QTextCursor::Start);
3017 else
3018 d->cursor.movePosition(QTextCursor::End);
3019 }
3020
3021 QTextCursor newAnchor;
3022 if (findNextPrevAnchor(d->cursor, next, newAnchor)) {
3023 d->cursor = newAnchor;
3024 d->cursorIsFocusIndicator = true;
3025 } else {
3026 d->cursor.clearSelection();
3027 }
3028
3029 if (d->cursor.hasSelection()) {
3030 crect = selectionRect();
3031 emit updateRequest(crect);
3032 emit visibilityRequest(crect);
3033 return true;
3034 } else {
3035 return false;
3036 }
3037}
3038
3040{
3041 Q_D(QWidgetTextControl);
3042
3043 if (!(d->interactionFlags & Qt::LinksAccessibleByKeyboard))
3044 return false;
3045
3046 // Verify that this is an anchor.
3047 const QString anchorHref = d->anchorForCursor(newCursor);
3048 if (anchorHref.isEmpty())
3049 return false;
3050
3051 // and process it
3052 QRectF crect = selectionRect();
3053 emit updateRequest(crect);
3054
3055 d->cursor.setPosition(newCursor.selectionStart());
3056 d->cursor.setPosition(newCursor.selectionEnd(), QTextCursor::KeepAnchor);
3057 d->cursorIsFocusIndicator = true;
3058
3059 crect = selectionRect();
3060 emit updateRequest(crect);
3061 emit visibilityRequest(crect);
3062 return true;
3063}
3064
3066{
3067 Q_D(QWidgetTextControl);
3068 if (flags == d->interactionFlags)
3069 return;
3070 d->interactionFlags = flags;
3071
3072 if (d->hasFocus)
3073 d->setCursorVisible(flags & Qt::TextEditable);
3074}
3075
3076Qt::TextInteractionFlags QWidgetTextControl::textInteractionFlags() const
3077{
3078 Q_D(const QWidgetTextControl);
3079 return d->interactionFlags;
3080}
3081
3083{
3084 Q_D(QWidgetTextControl);
3085 d->cursor.mergeCharFormat(modifier);
3086 d->updateCurrentCharFormat();
3087}
3088
3090{
3091 Q_D(QWidgetTextControl);
3092 d->cursor.setCharFormat(format);
3093 d->updateCurrentCharFormat();
3094}
3095
3097{
3098 Q_D(const QWidgetTextControl);
3099 return d->cursor.charFormat();
3100}
3101
3103{
3104 Q_D(QWidgetTextControl);
3105 d->cursor.insertText(text);
3106}
3107
3108#ifndef QT_NO_TEXTHTMLPARSER
3110{
3111 Q_D(QWidgetTextControl);
3112 d->cursor.insertHtml(text);
3113}
3114#endif // QT_NO_TEXTHTMLPARSER
3115
3117{
3118 Q_D(const QWidgetTextControl);
3119 if (name.isEmpty())
3120 return QPointF();
3121
3122 QRectF r;
3123 for (QTextBlock block = d->doc->begin(); block.isValid(); block = block.next()) {
3124 QTextCharFormat format = block.charFormat();
3125 if (format.isAnchor() && format.anchorNames().contains(name)) {
3126 r = d->rectForPosition(block.position());
3127 break;
3128 }
3129
3130 for (QTextBlock::Iterator it = block.begin(); !it.atEnd(); ++it) {
3131 QTextFragment fragment = it.fragment();
3132 format = fragment.charFormat();
3133 if (format.isAnchor() && format.anchorNames().contains(name)) {
3134 r = d->rectForPosition(fragment.position());
3135 block = QTextBlock();
3136 break;
3137 }
3138 }
3139 }
3140 if (!r.isValid())
3141 return QPointF();
3142 return QPointF(0, r.top());
3143}
3144
3146{
3147 Q_D(QWidgetTextControl);
3148 d->doc->adjustSize();
3149}
3150
3151bool QWidgetTextControl::find(const QString &exp, QTextDocument::FindFlags options)
3152{
3153 Q_D(QWidgetTextControl);
3154 QTextCursor search = d->doc->find(exp, d->cursor, options);
3155 if (search.isNull())
3156 return false;
3157
3158 setTextCursor(search);
3159 return true;
3160}
3161
3162#if QT_CONFIG(regularexpression)
3163bool QWidgetTextControl::find(const QRegularExpression &exp, QTextDocument::FindFlags options)
3164{
3165 Q_D(QWidgetTextControl);
3166 QTextCursor search = d->doc->find(exp, d->cursor, options);
3167 if (search.isNull())
3168 return false;
3169
3170 setTextCursor(search);
3171 return true;
3172}
3173#endif
3174
3176{
3177 return document()->toPlainText();
3178}
3179
3180#ifndef QT_NO_TEXTHTMLPARSER
3182{
3183 return document()->toHtml();
3184}
3185#endif
3186
3187#if QT_CONFIG(textmarkdownwriter)
3188QString QWidgetTextControl::toMarkdown(QTextDocument::MarkdownFeatures features) const
3189{
3190 return document()->toMarkdown(features);
3191}
3192#endif
3193
3195{
3196 // clear blockFormat properties that the user is unlikely to want duplicated:
3197 // - don't insert <hr/> automatically
3198 // - the next paragraph after a heading should be a normal paragraph
3199 // - remove the bottom margin from the last list item before appending
3200 // - the next checklist item after a checked item should be unchecked
3201 auto blockFmt = cursor.blockFormat();
3202 auto charFmt = cursor.charFormat();
3204 if (blockFmt.hasProperty(QTextFormat::HeadingLevel)) {
3205 blockFmt.clearProperty(QTextFormat::HeadingLevel);
3206 charFmt = QTextCharFormat();
3207 }
3208 if (cursor.currentList()) {
3209 auto existingFmt = cursor.blockFormat();
3211 cursor.setBlockFormat(existingFmt);
3212 if (blockFmt.marker() == QTextBlockFormat::MarkerType::Checked)
3213 blockFmt.setMarker(QTextBlockFormat::MarkerType::Unchecked);
3214 }
3215
3216 // After a blank line, reset block and char formats. I.e. you can end a list,
3217 // block quote, etc. by hitting enter twice, and get back to normal paragraph style.
3218 if (cursor.block().text().isEmpty() &&
3221 blockFmt = QTextBlockFormat();
3222 const bool blockFmtChanged = (cursor.blockFormat() != blockFmt);
3223 charFmt = QTextCharFormat();
3224 cursor.setBlockFormat(blockFmt);
3225 cursor.setCharFormat(charFmt);
3226 // If the user hit enter twice just to get back to default format,
3227 // don't actually insert a new block. But if the user then hits enter
3228 // yet again, the block format will not change, so we will insert a block.
3229 // This is what many word processors do.
3230 if (blockFmtChanged)
3231 return;
3232 }
3233
3234 cursor.insertBlock(blockFmt, charFmt);
3235}
3236
3238{
3239 QTextCursor tmp(doc);
3240 tmp.beginEditBlock();
3242
3243 if (!doc->isEmpty())
3245 else
3247
3248 // preserve the char format
3249 QTextCharFormat oldCharFormat = cursor.charFormat();
3250
3251#ifndef QT_NO_TEXTHTMLPARSER
3253 tmp.insertHtml(text);
3254 } else {
3255 tmp.insertText(text);
3256 }
3257#else
3259 tmp.insertText(text);
3260#endif // QT_NO_TEXTHTMLPARSER
3261 if (!cursor.hasSelection())
3262 cursor.setCharFormat(oldCharFormat);
3263
3264 tmp.endEditBlock();
3265}
3266
3268{
3269 Q_D(QWidgetTextControl);
3270 d->append(text, Qt::AutoText);
3271}
3272
3274{
3275 Q_D(QWidgetTextControl);
3276 d->append(html, Qt::RichText);
3277}
3278
3280{
3281 Q_D(QWidgetTextControl);
3282 d->append(text, Qt::PlainText);
3283}
3284
3285
3287{
3288 Q_D(QWidgetTextControl);
3289 QRectF crect = d->rectForPosition(d->cursor.position()).adjusted(-5, 0, 5, 0);
3290 emit visibilityRequest(crect);
3292}
3293
3295{
3296 Q_D(const QWidgetTextControl);
3297 return d->palette;
3298}
3299
3301{
3302 Q_D(QWidgetTextControl);
3303 d->palette = pal;
3304}
3305
3307{
3308 Q_D(const QWidgetTextControl);
3309
3311
3312 ctx.selections = d->extraSelections;
3313 ctx.palette = d->palette;
3314#if QT_CONFIG(style_stylesheet)
3315 if (widget) {
3316 if (auto cssStyle = qt_styleSheet(widget->style())) {
3319 cssStyle->styleSheetPalette(widget, &option, &ctx.palette);
3320 }
3321 }
3322#endif // style_stylesheet
3323 if (d->cursorOn && d->isEnabled) {
3324 if (d->hideCursor)
3325 ctx.cursorPosition = -1;
3326 else if (d->preeditCursor != 0)
3327 ctx.cursorPosition = - (d->preeditCursor + 2);
3328 else
3329 ctx.cursorPosition = d->cursor.position();
3330 }
3331
3332 if (!d->dndFeedbackCursor.isNull())
3333 ctx.cursorPosition = d->dndFeedbackCursor.position();
3334#ifdef QT_KEYPAD_NAVIGATION
3335 if (!QApplicationPrivate::keypadNavigationEnabled() || d->hasEditFocus)
3336#endif
3337 if (d->cursor.hasSelection()) {
3339 selection.cursor = d->cursor;
3340 if (d->cursorIsFocusIndicator) {
3342 opt.palette = ctx.palette;
3344 QStyle *style = QApplication::style();
3345 if (widget)
3346 style = widget->style();
3348 selection.format = qvariant_cast<QTextFormat>(ret.variant).toCharFormat();
3349 } else {
3351 selection.format.setBackground(ctx.palette.brush(cg, QPalette::Highlight));
3352 selection.format.setForeground(ctx.palette.brush(cg, QPalette::HighlightedText));
3354 QStyle *style = QApplication::style();
3355 if (widget) {
3357 style = widget->style();
3358 }
3360 selection.format.setProperty(QTextFormat::FullWidthSelection, true);
3361 }
3362 ctx.selections.append(selection);
3363 }
3364
3365 return ctx;
3366}
3367
3369{
3370 Q_D(QWidgetTextControl);
3371 p->save();
3373 if (rect.isValid())
3374 p->setClipRect(rect, Qt::IntersectClip);
3375 ctx.clip = rect;
3376
3377 d->doc->documentLayout()->draw(p, ctx);
3378 p->restore();
3379}
3380
3382{
3383#ifndef QT_NO_CLIPBOARD
3384 QMimeData *md = new QMimeData;
3385 md->setText(linkToCopy);
3386 QGuiApplication::clipboard()->setMimeData(md);
3387#endif
3388}
3389
3391{
3392 Q_D(const QWidgetTextControl);
3393 return d->doc->documentLayout()->hitTest(point, accuracy);
3394}
3395
3397{
3398 Q_D(const QWidgetTextControl);
3399 return d->doc->documentLayout()->blockBoundingRect(block);
3400}
3401
3402#ifndef QT_NO_CONTEXTMENU
3403#define NUM_CONTROL_CHARACTERS 14
3408 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRM Left-to-right mark"), 0x200e },
3409 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLM Right-to-left mark"), 0x200f },
3410 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWJ Zero width joiner"), 0x200d },
3411 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWNJ Zero width non-joiner"), 0x200c },
3412 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWSP Zero width space"), 0x200b },
3413 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRE Start of left-to-right embedding"), 0x202a },
3414 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLE Start of right-to-left embedding"), 0x202b },
3415 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRO Start of left-to-right override"), 0x202d },
3416 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLO Start of right-to-left override"), 0x202e },
3417 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "PDF Pop directional formatting"), 0x202c },
3418 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRI Left-to-right isolate"), 0x2066 },
3419 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLI Right-to-left isolate"), 0x2067 },
3420 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "FSI First strong isolate"), 0x2068 },
3421 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "PDI Pop directional isolate"), 0x2069 }
3423
3425 : QMenu(parent), editWidget(_editWidget)
3426{
3427 setTitle(tr("Insert Unicode control character"));
3428 for (int i = 0; i < NUM_CONTROL_CHARACTERS; ++i) {
3429 addAction(tr(qt_controlCharacters[i].text), this, SLOT(menuActionTriggered()));
3430 }
3431}
3432
3433void QUnicodeControlCharacterMenu::menuActionTriggered()
3434{
3435 QAction *a = qobject_cast<QAction *>(sender());
3436 int idx = actions().indexOf(a);
3437 if (idx < 0 || idx >= NUM_CONTROL_CHARACTERS)
3438 return;
3439 QChar c(qt_controlCharacters[idx].character);
3440 QString str(c);
3441
3442#if QT_CONFIG(textedit)
3443 if (QTextEdit *edit = qobject_cast<QTextEdit *>(editWidget)) {
3444 edit->insertPlainText(str);
3445 return;
3446 }
3447#endif
3448 if (QWidgetTextControl *control = qobject_cast<QWidgetTextControl *>(editWidget)) {
3449 control->insertPlainText(str);
3450 }
3451#if QT_CONFIG(lineedit)
3452 if (QLineEdit *edit = qobject_cast<QLineEdit *>(editWidget)) {
3453 edit->insert(str);
3454 return;
3455 }
3456#endif
3457}
3458#endif // QT_NO_CONTEXTMENU
3459
3461{
3462 if (!fragment.isEmpty())
3463 return QStringList() << u"text/plain"_s << u"text/html"_s
3464#if QT_CONFIG(textmarkdownwriter)
3465 << u"text/markdown"_s
3466#endif
3467#ifndef QT_NO_TEXTODFWRITER
3468 << u"application/vnd.oasis.opendocument.text"_s
3469#endif
3470 ;
3471 else
3472 return QMimeData::formats();
3473}
3474
3476{
3477 if (!fragment.isEmpty())
3478 setup();
3480}
3481
3482void QTextEditMimeData::setup() const
3483{
3484 QTextEditMimeData *that = const_cast<QTextEditMimeData *>(this);
3485#ifndef QT_NO_TEXTHTMLPARSER
3486 that->setData("text/html"_L1, fragment.toHtml().toUtf8());
3487#endif
3488#if QT_CONFIG(textmarkdownwriter)
3489 that->setData("text/markdown"_L1, fragment.toMarkdown().toUtf8());
3490#endif
3491#ifndef QT_NO_TEXTODFWRITER
3492 {
3494 QTextDocumentWriter writer(&buffer, "ODF");
3495 writer.write(fragment);
3496 buffer.close();
3497 that->setData("application/vnd.oasis.opendocument.text"_L1, buffer.data());
3498 }
3499#endif
3500 that->setText(fragment.toPlainText());
3501 fragment = QTextDocumentFragment();
3502}
3503
3505
3506#include "moc_qwidgettextcontrol_p.cpp"
3507
3508#endif // QT_NO_TEXTCONTROL
void documentSizeChanged(const QSizeF &newSize)
This signal is emitted when the size of the document layout changes to newSize.
void updateBlock(const QTextBlock &block)
void update(const QRectF &=QRectF(0., 0., 1000000000., 1000000000.))
This signal is emitted when the rectangle rect has been updated.
The QAction class provides an abstraction for user commands that can be added to different user inter...
Definition qaction.h:30
void setIcon(const QIcon &icon)
Definition qaction.cpp:547
static QStyle * style()
Returns the application's style object.
static QPalette palette()
Returns the current application palette.
int doubleClickInterval
the time limit in milliseconds that distinguishes a double click from two consecutive mouse clicks
int startDragDistance
the minimum distance required for a drag and drop operation to start.
void start(int msec, QObject *obj)
\obsolete Use chrono overload instead.
void stop()
Stops the timer.
bool isActive() const noexcept
Returns true if the timer is running and has not been stopped; otherwise returns false.
Definition qbasictimer.h:34
\inmodule QtCore \reentrant
Definition qbuffer.h:16
\inmodule QtCore
The QClipboard class provides access to the window system clipboard.
Definition qclipboard.h:20
void setMimeData(QMimeData *data, Mode mode=Clipboard)
Sets the clipboard data to src.
bool supportsSelection() const
Returns true if the clipboard supports mouse selection; otherwise returns false.
Mode
\keyword clipboard mode
Definition qclipboard.h:27
The QContextMenuEvent class contains parameters that describe a context menu event.
Definition qevent.h:594
static bool openUrl(const QUrl &url)
Opens the given url in the appropriate Web browser for the user's desktop environment,...
\inmodule QtGui
Definition qdrag.h:22
Qt::DropAction exec(Qt::DropActions supportedActions=Qt::MoveAction)
Definition qdrag.cpp:201
void setMimeData(QMimeData *data)
Sets the data to be sent to the given MIME data.
Definition qdrag.cpp:101
QObject * target() const
Returns the target of the drag and drop operation.
Definition qdrag.cpp:178
\inmodule QtCore
Definition qcoreevent.h:45
virtual void setAccepted(bool accepted)
Definition qcoreevent.h:307
Type
This enum type defines the valid event types in Qt.
Definition qcoreevent.h:51
@ GraphicsSceneDragLeave
Definition qcoreevent.h:200
@ GraphicsSceneMouseMove
Definition qcoreevent.h:189
@ GraphicsSceneContextMenu
Definition qcoreevent.h:193
@ EnabledChange
Definition qcoreevent.h:134
@ GraphicsSceneMouseRelease
Definition qcoreevent.h:191
@ GraphicsSceneDragEnter
Definition qcoreevent.h:198
@ GraphicsSceneDragMove
Definition qcoreevent.h:199
@ ShortcutOverride
Definition qcoreevent.h:158
@ FocusOut
Definition qcoreevent.h:67
@ InputMethod
Definition qcoreevent.h:120
@ GraphicsSceneMousePress
Definition qcoreevent.h:190
@ DragEnter
Definition qcoreevent.h:101
@ MouseMove
Definition qcoreevent.h:63
@ KeyPress
Definition qcoreevent.h:64
@ FocusIn
Definition qcoreevent.h:66
@ MouseButtonPress
Definition qcoreevent.h:60
@ GraphicsSceneHoverLeave
Definition qcoreevent.h:196
@ GraphicsSceneMouseDoubleClick
Definition qcoreevent.h:192
@ DragLeave
Definition qcoreevent.h:103
@ GraphicsSceneDrop
Definition qcoreevent.h:201
@ GraphicsSceneHoverEnter
Definition qcoreevent.h:194
@ MouseButtonDblClick
Definition qcoreevent.h:62
@ GraphicsSceneHoverMove
Definition qcoreevent.h:195
@ GraphicsSceneHelp
Definition qcoreevent.h:197
@ ContextMenu
Definition qcoreevent.h:119
@ MouseButtonRelease
Definition qcoreevent.h:61
Type type() const
Returns the event type.
Definition qcoreevent.h:304
void ignore()
Clears the accept flag parameter of the event object, the equivalent of calling setAccepted(false).
Definition qcoreevent.h:311
bool isAccepted() const
Definition qcoreevent.h:308
void accept()
Sets the accept flag of the event object, the equivalent of calling setAccepted(true).
Definition qcoreevent.h:310
The QFocusEvent class contains event parameters for widget focus events.
Definition qevent.h:470
bool gotFocus() const
Returns true if type() is QEvent::FocusIn; otherwise returns false.
Definition qevent.h:475
Qt::FocusReason reason() const
Returns the reason for this focus event.
Definition qevent.cpp:1569
\reentrant \inmodule QtGui
int horizontalAdvance(const QString &, int len=-1) const
Returns the horizontal advance in pixels of the first len characters of text.
The QGraphicsSceneContextMenuEvent class provides context menu events in the graphics view framework.
The QGraphicsSceneDragDropEvent class provides events for drag and drop in the graphics view framewor...
void acceptProposedAction()
Sets the proposed action as accepted, i.e, the drop action is set to the proposed action.
The QGraphicsSceneEvent class provides a base class for all graphics view related events.
QWidget * widget() const
Returns the widget where the event originated, or \nullptr if the event originates from another appli...
The QGraphicsSceneHoverEvent class provides hover events in the graphics view framework.
The QGraphicsSceneMouseEvent class provides mouse events in the graphics view framework.
static QClipboard * clipboard()
Returns the object for interacting with the clipboard.
static QStyleHints * styleHints()
Returns the application's style hints.
static QInputMethod * inputMethod()
returns the input method.
The QHelpEvent class provides an event that is used to request helpful information about a particular...
Definition qevent.h:788
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
bool isNull() const
Returns true if the icon is empty; otherwise returns false.
Definition qicon.cpp:1019
static QIcon fromTheme(const QString &name)
Definition qicon.cpp:1344
static bool isCommonTextEditShortcut(const QKeyEvent *ke)
The QInputMethodEvent class provides parameters for input method events.
Definition qevent.h:625
const QString & preeditString() const
Returns the preedit text, i.e.
Definition qevent.h:650
int replacementLength() const
Returns the number of characters to be replaced in the preedit string.
Definition qevent.h:654
const QString & commitString() const
Returns the text that should get added to (or replace parts of) the text of the editor widget.
Definition qevent.h:652
int replacementStart() const
Returns the position at which characters are to be replaced relative from the start of the preedit st...
Definition qevent.h:653
const QList< Attribute > & attributes() const
Returns the list of attributes passed to the QInputMethodEvent constructor.
Definition qevent.h:649
The QKeyEvent class describes a key event.
Definition qevent.h:424
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately after the event occurred.
Definition qevent.cpp:1468
QString text() const
Returns the Unicode text that this key generated.
Definition qevent.h:443
int key() const
Returns the code of the key that was pressed or released.
Definition qevent.h:434
bool isEmpty() const override
\reimp
Definition qlayout.cpp:422
QLayout * layout() override
\reimp
The QLineEdit widget is a one-line text editor.
Definition qlineedit.h:28
void insert(const QString &)
Deletes any selected text, inserts newText, and validates the result.
void remove(qsizetype i, qsizetype n=1)
Definition qlist.h:794
void append(parameter_type t)
Definition qlist.h:458
static QMenuPrivate * get(QMenu *m)
Definition qmenu_p.h:309
The QMenu class provides a menu widget for use in menu bars, context menus, and other popup menus.
Definition qmenu.h:26
void popup(const QPoint &pos, QAction *at=nullptr)
Displays the menu so that the action atAction will be at the specified global position p.
Definition qmenu.cpp:2310
QAction * addSeparator()
This convenience function creates a new separator action, i.e.
Definition qmenu.cpp:1921
void setTitle(const QString &title)
Definition qmenu.cpp:1097
QAction * addMenu(QMenu *menu)
This convenience function adds menu as a submenu to this menu.
Definition qmenu.cpp:1877
void addAction(QAction *action)
Appends the action action to this widget's list of actions.
Definition qwidget.cpp:3117
static QMetaMethod fromSignal(PointerToMemberFunction signal)
\inmodule QtCore
Definition qmetatype.h:341
\inmodule QtCore
Definition qmimedata.h:16
void setData(const QString &mimetype, const QByteArray &data)
Sets the data associated with the MIME type given by mimeType to the specified data.
void setText(const QString &text)
Sets text as the plain text (MIME type text/plain) used to represent the data.
virtual QVariant retrieveData(const QString &mimetype, QMetaType preferredType) const
Returns a variant with the given type containing data for the MIME type specified by mimeType.
virtual QStringList formats() const
Returns a list of formats supported by the object.
\inmodule QtGui
Definition qevent.h:196
QObject * parent
Definition qobject.h:73
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:299
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
Definition qobject.cpp:2658
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1389
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
static QPagedPaintDevicePrivate * get(QPagedPaintDevice *pd)
\inmodule QtGui
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
The QPalette class contains color groups for each widget state.
Definition qpalette.h:19
ColorGroup
\value Disabled \value Active \value Inactive \value Normal synonym for Active
Definition qpalette.h:49
@ Inactive
Definition qpalette.h:49
@ HighlightedText
Definition qpalette.h:53
@ Highlight
Definition qpalette.h:53
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition qpoint.h:404
bool isNull() const noexcept
Returns true if both the x and y coordinates are set to 0.0 (ignoring the sign); otherwise returns fa...
Definition qpoint.h:338
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr void setRight(qreal pos) noexcept
Sets the right edge of the rectangle to the given finite x coordinate.
Definition qrect.h:678
constexpr QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:813
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:497
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
Definition qrect.h:666
constexpr qreal right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:499
\inmodule QtCore \reentrant
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
Definition qsize.h:208
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:994
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5506
QByteArray toUtf8() const &
Definition qstring.h:634
The QStyleHintReturnVariant class provides style hints that return a QVariant.
void cursorFlashTimeChanged(int cursorFlashTime)
The QStyleOption class stores the parameters used by QStyle functions.
QPalette palette
void initFrom(const QWidget *w)
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition qstyle.h:29
@ SH_TextControl_FocusIndicatorTextCharFormat
Definition qstyle.h:662
@ SH_BlinkCursorWhenTextSelected
Definition qstyle.h:613
@ SH_RichText_FullWidthSelection
Definition qstyle.h:614
virtual int styleHint(StyleHint stylehint, const QStyleOption *opt=nullptr, const QWidget *widget=nullptr, QStyleHintReturn *returnData=nullptr) const =0
Returns an integer representing the specified style hint for the given widget described by the provid...
@ PM_TextCursorWidth
Definition qstyle.h:520
void setMarker(MarkerType marker)
void setIndent(int indent)
Sets the paragraph's indentation.
\reentrant
iterator begin() const
Returns a text block iterator pointing to the beginning of the text block.
iterator Iterator
Qt-style synonym for QTextBlock::iterator.
int length() const
Returns the length of the block in characters.
QTextBlockFormat blockFormat() const
Returns the QTextBlockFormat that describes block-specific properties.
iterator end() const
Returns a text block iterator pointing to the end of the text block.
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
QTextBlock next() const
Returns the text block in the document after this block, or an empty text block if this is the last o...
QTextLayout * layout() const
Returns the QTextLayout that is used to lay out and display the block's contents.
int position() const
Returns the index of the block's first character within the document.
QString text() const
Returns the block's contents as plain text.
QTextBlock previous() const
Returns the text block in the document before this block, or an empty text block if this is the first...
bool isValid() const
Returns true if this character format is valid; otherwise returns false.
QString anchorHref() const
Returns the text format's hypertext link, or an empty string if none has been set.
\reentrant \inmodule QtGui
Definition qtextcursor.h:30
QString selectedText() const
Returns the current selection's text (which may be empty).
QTextBlockFormat blockFormat() const
Returns the block format of the block the cursor is in.
QTextCharFormat charFormat() const
Returns the format of the character immediately before the cursor position().
QTextBlock block() const
Returns the block that contains the cursor.
void beginEditBlock()
Indicates the start of a block of editing operations on the document that should appear as a single o...
bool atBlockStart() const
Returns true if the cursor is at the start of a block; otherwise returns false.
void setPosition(int pos, MoveMode mode=MoveAnchor)
Moves the cursor to the absolute position in the document specified by pos using a MoveMode specified...
int selectionStart() const
Returns the start of the selection or position() if the cursor doesn't have a selection.
bool movePosition(MoveOperation op, MoveMode=MoveAnchor, int n=1)
Moves the cursor by performing the given operation n times, using the specified mode,...
bool atBlockEnd() const
Returns true if the cursor is at the end of a block; otherwise returns false.
int anchor() const
Returns the anchor position; this is the same as position() unless there is a selection in which case...
void insertHtml(const QString &html)
void clearSelection()
Clears the current selection by setting the anchor to the cursor position.
void insertFragment(const QTextDocumentFragment &fragment)
Inserts the text fragment at the current position().
bool isNull() const
Returns true if the cursor is null; otherwise returns false.
MoveMode
\value MoveAnchor Moves the anchor to the same position as the cursor itself.
Definition qtextcursor.h:47
void setBlockFormat(const QTextBlockFormat &format)
Sets the block format of the current block (or all blocks that are contained in the selection) to for...
void setCharFormat(const QTextCharFormat &format)
Sets the cursor's current character format to the given format.
bool visualNavigation() const
void removeSelectedText()
If there is a selection, its content is deleted; otherwise does nothing.
int selectionEnd() const
Returns the end of the selection or position() if the cursor doesn't have a selection.
void select(SelectionType selection)
Selects text in the document according to the given selection.
void insertText(const QString &text)
Inserts text at the current position, using the current character format.
QTextList * currentList() const
Returns the current list if the cursor position() is inside a block that is part of a list; otherwise...
void setVisualNavigation(bool b)
void insertBlock()
Inserts a new empty block at the cursor position() with the current blockFormat() and charFormat().
bool hasSelection() const
Returns true if the cursor contains a selection; otherwise returns false.
void endEditBlock()
Indicates the end of a block of editing operations on the document that should appear as a single ope...
MoveOperation
\value NoMove Keep the cursor where it is
Definition qtextcursor.h:61
void mergeBlockFormat(const QTextBlockFormat &modifier)
Modifies the block format of the current block (or all blocks that are contained in the selection) wi...
bool hasComplexSelection() const
Returns true if the cursor contains a selection that is not simply a range from selectionStart() to s...
QTextTable * currentTable() const
Returns a pointer to the current table if the cursor position() is inside a block that is part of a t...
void deletePreviousChar()
If there is no selected text, deletes the character before the current cursor position; otherwise del...
int position() const
Returns the absolute position of the cursor within the document.
void deleteChar()
If there is no selected text, deletes the character at the current cursor position; otherwise deletes...
QTextFrame * currentFrame() const
Returns a pointer to the current frame.
QTextList * createList(const QTextListFormat &format)
Creates and returns a new list with the given format, and makes the current paragraph the cursor is i...
QString toPlainText() const
This function returns the same as toRawText(), but will replace some unicode characters with ASCII al...
bool isEmpty() const
Returns true if the fragment is empty; otherwise returns false.
static QTextDocumentFragment fromHtml(const QString &html, const QTextDocument *resourceProvider=nullptr)
static QTextDocumentFragment fromPlainText(const QString &plainText)
Returns a document fragment that contains the given plainText.
The QTextDocumentWriter class provides a format-independent interface for writing a QTextDocument to ...
\reentrant \inmodule QtGui
void setModified(bool m=true)
void contentsChange(int from, int charsRemoved, int charsAdded)
This signal is emitted whenever the document's content changes; for example, when text is inserted or...
void setHtml(const QString &html)
Replaces the entire contents of the document with the given HTML-formatted text in the html string.
bool isEmpty() const
Returns true if the document is empty; otherwise returns false.
QFont defaultFont
the default font used to display the document's text
void redoAvailable(bool)
This signal is emitted whenever redo operations become available (available is true) or unavailable (...
QString toHtml() const
Returns a string containing an HTML representation of the document.
QAbstractTextDocumentLayout * documentLayout() const
Returns the document layout for this document.
bool useDesignMetrics
whether the document uses design metrics of fonts to improve the accuracy of text layout
QSizeF pageSize
the page size that should be used for laying out the document
void modificationChanged(bool m)
This signal is emitted whenever the content of the document changes in a way that affects the modific...
virtual void clear()
Clears the document.
bool isUndoRedoEnabled() const
void print(QPagedPaintDevice *printer) const
Prints the document to the given printer.
void undoAvailable(bool)
This signal is emitted whenever undo operations become available (available is true) or unavailable (...
QTextDocument::ResourceProvider resourceProvider() const
void cursorPositionChanged(const QTextCursor &cursor)
This signal is emitted whenever the position of a cursor changed due to an editing operation.
void setUndoRedoEnabled(bool enable)
QString toPlainText() const
Returns the plain text contained in the document.
void contentsChanged()
This signal is emitted whenever the document's content changes; for example, when text is inserted or...
QTextBlock findBlock(int pos) const
Returns the text block that contains the {pos}-th character.
QString metaInformation(MetaInformation info) const
Returns meta information about the document of the type specified by info.
void setPlainText(const QString &text)
Replaces the entire contents of the document with the given plain text.
void documentLayoutChanged()
void blockCountChanged(int newBlockCount)
int characterCount() const
virtual QVariant retrieveData(const QString &mimeType, QMetaType type) const override
Returns a variant with the given type containing data for the MIME type specified by mimeType.
virtual QStringList formats() const override
Returns a list of formats supported by the object.
The QTextEdit class provides a widget that is used to edit and display both plain and rich text.
Definition qtextedit.h:27
QString stringProperty(int propertyId) const
Returns the value of the property given by propertyId; if the property isn't of QMetaType::QString ty...
@ BlockTrailingHorizontalRulerWidth
void setLayoutDirection(Qt::LayoutDirection direction)
Sets the document's layout direction to the specified direction.
bool hasProperty(int propertyId) const
Returns true if the text format has a property with the given propertyId; otherwise returns false.
void clearProperty(int propertyId)
Clears the value of the property given by propertyId.
void merge(const QTextFormat &other)
Merges the other format with this format; where there are conflicts the other format takes precedence...
\reentrant
QTextCharFormat charFormat() const
Returns the text fragment's character format.
int length() const
Returns the number of characters in the text fragment.
int position() const
Returns the position of this text fragment in the document.
\reentrant
Definition qtextobject.h:81
\reentrant
Definition qtextlayout.h:70
int lineCount() const
Returns the number of lines in this text layout.
QFont font() const
Returns the current font that is used for the layout, or a default font if none is set.
QString preeditAreaText() const
Returns the text that is inserted in the layout before editing occurs.
\reentrant
int lineNumber() const
Returns the position of the line in the text engine.
void setStyle(Style style)
Sets the list format's style.
\reentrant
Definition qtextlist.h:18
\reentrant
Definition qtexttable.h:19
int columnSpan() const
Returns the number of columns this cell spans.
int row() const
Returns the number of the row in the table that contains this cell.
QTextCursor firstCursorPosition() const
Returns the first valid cursor position in this cell.
int column() const
Returns the number of the column in the table that contains this cell.
\reentrant
Definition qtexttable.h:63
\inmodule QtCore
Definition qcoreevent.h:366
int timerId() const
Returns the unique timer identifier, which is the same identifier as returned from QObject::startTime...
Definition qcoreevent.h:370
static void showText(const QPoint &pos, const QString &text, QWidget *w=nullptr, const QRect &rect={}, int msecShowTime=-1)
Shows text as a tool tip, with the global position pos as the point of interest.
Definition qtooltip.cpp:439
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
QUnicodeControlCharacterMenu(QObject *editWidget, QWidget *parent)
\inmodule QtCore
Definition qurl.h:94
\inmodule QtCore
Definition qvariant.h:65
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
void _q_updateBlock(const QTextBlock &)
void mouseReleaseEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos)
void setCursorVisible(bool visible)
void _q_contentsChanged(int from, int charsRemoved, int charsAdded)
void setContent(Qt::TextFormat format=Qt::RichText, const QString &text=QString(), QTextDocument *document=nullptr)
void setCursorPosition(const QPointF &pos)
Qt::TextInteractionFlags interactionFlags
void contextMenuEvent(const QPoint &screenPos, const QPointF &docPos, QWidget *contextWidget)
void selectionChanged(bool forceEmitSelectionChanged=false)
void repaintOldAndNewSelection(const QTextCursor &oldSelection)
void extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition)
void _q_emitCursorPosChanged(const QTextCursor &someCursor)
bool dragEnterEvent(QEvent *e, const QMimeData *mimeData)
bool sendMouseEventToInputContext(QEvent *e, QEvent::Type eventType, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos)
void init(Qt::TextFormat format=Qt::RichText, const QString &text=QString(), QTextDocument *document=nullptr)
QRectF rectForPosition(int position) const
void setBlinkingCursorEnabled(bool enable)
bool cursorMoveKeyEvent(QKeyEvent *e)
QRectF cursorRectPlusUnicodeDirectionMarkers(const QTextCursor &cursor) const
QString anchorForCursor(const QTextCursor &anchor) const
void append(const QString &text, Qt::TextFormat format=Qt::AutoText)
bool dragMoveEvent(QEvent *e, const QMimeData *mimeData, const QPointF &pos)
void inputMethodEvent(QInputMethodEvent *)
void activateLinkUnderCursor(QString href=QString())
void mousePressEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos)
bool dropEvent(const QMimeData *mimeData, const QPointF &pos, Qt::DropAction dropAction, QObject *source)
void mouseMoveEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos)
void extendBlockwiseSelection(int suggestedNewPosition)
void mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos)
void setPlainText(const QString &text)
virtual bool event(QEvent *e) override
This virtual function receives events to an object and should return true if the event e was recogniz...
void mergeCurrentCharFormat(const QTextCharFormat &modifier)
bool setFocusToNextOrPreviousAnchor(bool next)
QTextCursor textCursor() const
void setCursorWidth(int width)
void redoAvailable(bool b)
Qt::TextInteractionFlags textInteractionFlags
void setCursorIsFocusIndicator(bool b)
void insertHtml(const QString &text)
QTextCharFormat currentCharFormat() const
void appendPlainText(const QString &text)
void setOpenExternalLinks(bool open)
void setIgnoreUnusedNavigationEvents(bool ignore)
void setHtml(const QString &text)
void cursorPositionChanged()
virtual QMimeData * createMimeDataFromSelection() const
void setOverwriteMode(bool overwrite)
QAbstractTextDocumentLayout::PaintContext getPaintContext(QWidget *widget) const
void setTextCursor(const QTextCursor &cursor, bool selectionClipboard=false)
virtual Q_INVOKABLE QVariant loadResource(int type, const QUrl &name)
void print(QPagedPaintDevice *printer) const
void undoAvailable(bool b)
void setAcceptRichText(bool accept)
void moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode=QTextCursor::MoveAnchor)
void paste(QClipboard::Mode mode=QClipboard::Clipboard)
void modificationChanged(bool m)
QTextBlock blockWithMarkerAt(const QPointF &pos) const
virtual void ensureCursorVisible()
void setFocus(bool focus, Qt::FocusReason=Qt::OtherFocusReason)
void setDragEnabled(bool enabled)
void updateRequest(const QRectF &rect=QRectF())
void setDocument(QTextDocument *document)
void drawContents(QPainter *painter, const QRectF &rect=QRectF(), QWidget *widget=nullptr)
virtual QVariant inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
virtual QString anchorAt(const QPointF &pos) const
QTextCursor cursorForPosition(const QPointF &pos) const
virtual QRectF blockBoundingRect(const QTextBlock &block) const
virtual void processEvent(QEvent *e, const QTransform &transform, QWidget *contextWidget=nullptr)
void append(const QString &text)
void documentSizeChanged(const QSizeF &)
bool setFocusToAnchor(const QTextCursor &newCursor)
bool isWordSelectionEnabled() const
QPointF anchorPosition(const QString &name) const
virtual int hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
QMenu * createStandardContextMenu(const QPointF &pos, QWidget *parent)
bool find(const QString &exp, QTextDocument::FindFlags options={ })
virtual void insertFromMimeData(const QMimeData *source)
bool findNextPrevAnchor(const QTextCursor &from, bool next, QTextCursor &newAnchor)
QString anchorAtCursor() const
void insertPlainText(const QString &text)
bool cursorIsFocusIndicator() const
void setWordSelectionEnabled(bool enabled)
void setCurrentCharFormat(const QTextCharFormat &format)
QWidgetTextControl(QObject *parent=nullptr)
void visibilityRequest(const QRectF &rect)
virtual bool canInsertFromMimeData(const QMimeData *source) const
void setPalette(const QPalette &pal)
virtual void timerEvent(QTimerEvent *e) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
QTextDocument * document() const
void setTextWidth(qreal width)
void appendHtml(const QString &html)
void blockCountChanged(int newBlockCount)
void setTextInteractionFlags(Qt::TextInteractionFlags flags)
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
void setAttribute(Qt::WidgetAttribute, bool on=true)
Sets the attribute attribute on this widget if on is true; otherwise clears the attribute.
QWidget * window() const
Returns the window for this widget, i.e.
Definition qwidget.cpp:4313
QPalette palette
the widget's palette
Definition qwidget.h:132
QList< QAction * > actions() const
Returns the (possibly empty) list of this widget's actions.
Definition qwidget.cpp:3207
QWindow * windowHandle() const
If this is a native widget, return the associated QWindow.
Definition qwidget.cpp:2483
QStyle * style() const
Definition qwidget.cpp:2600
virtual void keyPressEvent(QKeyEvent *event)
This event handler, for event event, can be reimplemented in a subclass to receive key press events f...
Definition qwidget.cpp:9606
EGLContext ctx
EGLImageKHR int int EGLuint64KHR * modifiers
QOpenGLWidget * widget
[1]
QHash< int, QWidget * > hash
[35multi]
QString str
[2]
QString text
QPushButton * button
[2]
bool focus
[0]
QCursor cursor
QSet< QString >::iterator it
rect
[4]
QStyleOptionButton opt
short next
Definition keywords.cpp:445
EGLint EGLint * formats
Combined button and popup list for selecting options.
Definition qcompare.h:63
InputMethodQuery
@ ImMaximumTextLength
@ ImTextBeforeCursor
@ ImAnchorRectangle
@ ImSurroundingText
@ ImCursorPosition
@ ImCurrentSelection
@ ImAbsolutePosition
@ ImFont
@ ImAnchorPosition
@ ImCursorRectangle
@ ImQueryInput
@ ImTextAfterCursor
@ CTRL
@ SHIFT
@ NavigationModeKeypadDirectional
MouseButton
Definition qnamespace.h:56
@ LeftButton
Definition qnamespace.h:58
@ MiddleButton
Definition qnamespace.h:60
@ NoButton
Definition qnamespace.h:57
@ TextSelectableByMouse
@ TextEditable
@ LinksAccessibleByMouse
@ LinksAccessibleByKeyboard
@ TextSelectableByKeyboard
@ NoTextInteraction
@ WA_DeleteOnClose
Definition qnamespace.h:321
@ IntersectClip
TextFormat
@ RichText
@ MarkdownText
@ PlainText
@ AutoText
@ LeftToRight
@ RightToLeft
Q_GUI_EXPORT bool mightBeRichText(QAnyStringView)
Returns true if the string text is likely to be rich text; otherwise returns false.
HitTestAccuracy
Definition qnamespace.h:203
@ FuzzyHit
Definition qnamespace.h:203
@ ExactHit
Definition qnamespace.h:203
@ Key_Select
@ Key_Return
Definition qnamespace.h:667
@ Key_Right
Definition qnamespace.h:679
@ Key_Enter
Definition qnamespace.h:668
@ Key_Backspace
Definition qnamespace.h:666
@ Key_Direction_L
Definition qnamespace.h:731
@ Key_Insert
Definition qnamespace.h:669
@ Key_Left
Definition qnamespace.h:677
@ Key_Up
Definition qnamespace.h:678
@ Key_Down
Definition qnamespace.h:680
@ Key_Direction_R
Definition qnamespace.h:732
@ ShiftModifier
@ GroupSwitchModifier
DropAction
@ CopyAction
@ MoveAction
@ UniqueConnection
FocusReason
@ PopupFocusReason
@ ActiveWindowFocusReason
QList< QString > QStringList
Constructs a string list that contains the given string, str.
const char * mimeType
#define ACCEL_KEY(k)
Definition qlineedit.cpp:54
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
#define SLOT(a)
Definition qobjectdefs.h:52
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLfloat GLfloat f
GLsizei range
GLenum GLuint buffer
GLint GLsizei width
GLenum type
GLbitfield flags
GLuint start
GLuint name
GLint GLsizei GLsizei GLenum format
GLsizei GLsizei GLchar * source
GLuint GLenum GLenum transform
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLsizei maxLength
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLuint GLenum option
GLenum GLenum GLsizei void * table
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define QStringLiteral(str)
QStyleSheetStyle * qt_styleSheet(QStyle *style)
#define QT_CONFIG(feature)
#define tr(X)
#define emit
#define Q_UNUSED(x)
#define QT_TRANSLATE_NOOP(scope, x)
unsigned short ushort
Definition qtypes.h:33
double qreal
Definition qtypes.h:187
QVideoFrameFormat::PixelFormat fmt
static QRectF boundingRectOfFloatsInSelection(const QTextCursor &cursor)
const struct QUnicodeControlCharacter qt_controlCharacters[NUM_CONTROL_CHARACTERS]
#define NUM_CONTROL_CHARACTERS
static QTextLine currentTextLine(const QTextCursor &cursor)
void setActionIcon(QAction *action, const QString &name)
void setActionIcon(QAction *action, const QString &name)
#define enabled
const char property[13]
Definition qwizard.cpp:101
QList< int > list
[14]
if(qFloatDistance(a, b)<(1<< 7))
[0]
file open(QIODevice::ReadOnly)
QMimeData * mimeData
QObject::connect nullptr
QVBoxLayout * layout
myObject disconnect()
[26]
QItemSelection * selection
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QFrame frame
[0]
QMenu menu
[5]
QDBusArgument argument
\variable QAbstractTextDocumentLayout::PaintContext::cursorPosition
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:962
static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index)
Definition qobject.cpp:3641
static Connection connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type=0, int *types=nullptr)
Definition qobject.cpp:3556
The QTextEdit::ExtraSelection structure provides a way of specifying a character format for a given s...
Definition qtextedit.h:170