Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtextedit.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
4#include "qtextedit_p.h"
5#if QT_CONFIG(lineedit)
6#include "qlineedit.h"
7#endif
8#if QT_CONFIG(textbrowser)
9#include "qtextbrowser.h"
10#endif
11
12#include <qfont.h>
13#include <qpainter.h>
14#include <qevent.h>
15#include <qdebug.h>
16#if QT_CONFIG(draganddrop)
17#include <qdrag.h>
18#endif
19#include <qclipboard.h>
20#if QT_CONFIG(menu)
21#include <qmenu.h>
22#endif
23#include <qstyle.h>
24#if QT_CONFIG(accessibility)
25#include <qaccessible.h>
26#endif
27#include "private/qtextdocumentlayout_p.h"
28#include "qtextdocument.h"
29#include "private/qtextdocument_p.h"
30#include "qtextlist.h"
31#include "private/qwidgettextcontrol_p.h"
32
33#include <qtextformat.h>
34#include <qdatetime.h>
35#include <qapplication.h>
36#include <private/qapplication_p.h>
37#include <limits.h>
38#include <qtextobject.h>
39#include <qtexttable.h>
40#include <qvariant.h>
41
43
44static inline bool shouldEnableInputMethod(QTextEdit *textedit)
45{
46#if defined (Q_OS_ANDROID)
47 return !textedit->isReadOnly() || (textedit->textInteractionFlags() & Qt::TextSelectableByMouse);
48#else
49 return !textedit->isReadOnly();
50#endif
51}
52
54{
55public:
56 inline QTextEditControl(QObject *parent) : QWidgetTextControl(parent) {}
57
58 virtual QMimeData *createMimeDataFromSelection() const override {
59 QTextEdit *ed = qobject_cast<QTextEdit *>(parent());
60 if (!ed)
61 return QWidgetTextControl::createMimeDataFromSelection();
62 return ed->createMimeDataFromSelection();
63 }
64 virtual bool canInsertFromMimeData(const QMimeData *source) const override {
65 QTextEdit *ed = qobject_cast<QTextEdit *>(parent());
66 if (!ed)
67 return QWidgetTextControl::canInsertFromMimeData(source);
68 return ed->canInsertFromMimeData(source);
69 }
70 virtual void insertFromMimeData(const QMimeData *source) override {
71 QTextEdit *ed = qobject_cast<QTextEdit *>(parent());
72 if (!ed)
73 QWidgetTextControl::insertFromMimeData(source);
74 else
75 ed->insertFromMimeData(source);
76 }
77 QVariant loadResource(int type, const QUrl &name) override {
78 auto *ed = qobject_cast<QTextEdit *>(parent());
79 if (!ed)
80 return QWidgetTextControl::loadResource(type, name);
81
82 QUrl resolvedName = ed->d_func()->resolveUrl(name);
83 return ed->loadResource(type, resolvedName);
84 }
85};
86
87QTextEditPrivate::QTextEditPrivate()
88 : control(nullptr),
89 autoFormatting(QTextEdit::AutoNone), tabChangesFocus(false),
90 lineWrap(QTextEdit::WidgetWidth), lineWrapColumnOrWidth(0),
91 wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere), clickCausedFocus(0)
92{
93 ignoreAutomaticScrollbarAdjustment = false;
94 preferRichText = false;
95 showCursorOnInitialShow = true;
96 inDrag = false;
97}
98
100{
101 for (const QMetaObject::Connection &connection : connections)
102 QObject::disconnect(connection);
103}
104
106{
107 QTextCursor cursor = control->textCursor();
108 cursor.beginEditBlock();
109
110 QTextBlockFormat blockFmt = cursor.blockFormat();
111
112 QTextListFormat listFmt;
113 listFmt.setStyle(QTextListFormat::ListDisc);
114 listFmt.setIndent(blockFmt.indent() + 1);
115
116 blockFmt.setIndent(0);
117 cursor.setBlockFormat(blockFmt);
118
119 cursor.createList(listFmt);
120
121 cursor.endEditBlock();
122 control->setTextCursor(cursor);
123}
124
125void QTextEditPrivate::init(const QString &html)
126{
127 Q_Q(QTextEdit);
128 control = new QTextEditControl(q);
129 control->setPalette(q->palette());
130
131 connections = {
132 QObjectPrivate::connect(control, &QTextEditControl::documentSizeChanged,
133 this, &QTextEditPrivate::adjustScrollbars),
134 QObjectPrivate::connect(control, &QTextEditControl::updateRequest,
135 this, &QTextEditPrivate::repaintContents),
136 QObjectPrivate::connect(control, &QTextEditControl::visibilityRequest,
137 this, &QTextEditPrivate::ensureVisible),
138 QObjectPrivate::connect(control, &QTextEditControl::blockMarkerHovered,
139 this, &QTextEditPrivate::hoveredBlockWithMarkerChanged),
140 QObjectPrivate::connect(control, &QTextEditControl::cursorPositionChanged,
141 this, &QTextEditPrivate::cursorPositionChanged),
142 QObject::connect(control, &QTextEditControl::microFocusChanged,
143 q, [q]() { q->updateMicroFocus(); }),
144 QObject::connect(control, &QTextEditControl::currentCharFormatChanged,
145 q, &QTextEdit::currentCharFormatChanged),
146 QObject::connect(control, &QTextEditControl::textChanged,
147 q, &QTextEdit::textChanged),
148 QObject::connect(control, &QTextEditControl::undoAvailable,
149 q, &QTextEdit::undoAvailable),
150 QObject::connect(control, &QTextEditControl::redoAvailable,
151 q, &QTextEdit::redoAvailable),
152 QObject::connect(control, &QTextEditControl::copyAvailable,
153 q, &QTextEdit::copyAvailable),
154 QObject::connect(control, &QTextEditControl::selectionChanged,
155 q, &QTextEdit::selectionChanged),
156 QObject::connect(control, &QTextEditControl::textChanged,
157 q, [q]() { q->updateMicroFocus(); }),
158 };
159
160 QTextDocument *doc = control->document();
161 // set a null page size initially to avoid any relayouting until the textedit
162 // is shown. relayoutDocument() will take care of setting the page size to the
163 // viewport dimensions later.
164 doc->setPageSize(QSize(0, 0));
165 doc->documentLayout()->setPaintDevice(viewport);
166 doc->setDefaultFont(q->font());
167 doc->setUndoRedoEnabled(false); // flush undo buffer.
168 doc->setUndoRedoEnabled(true);
169
170 if (!html.isEmpty())
171 control->setHtml(html);
172
173 hbar->setSingleStep(20);
174 vbar->setSingleStep(20);
175
176 viewport->setBackgroundRole(QPalette::Base);
177 q->setMouseTracking(true);
178 q->setAcceptDrops(true);
179 q->setFocusPolicy(Qt::StrongFocus);
180 q->setAttribute(Qt::WA_KeyCompression);
181 q->setAttribute(Qt::WA_InputMethodEnabled);
182 q->setInputMethodHints(Qt::ImhMultiLine);
183#ifndef QT_NO_CURSOR
184 viewport->setCursor(Qt::IBeamCursor);
185#endif
186}
187
188void QTextEditPrivate::repaintContents(const QRectF &contentsRect)
189{
190 if (!contentsRect.isValid()) {
191 viewport->update();
192 return;
193 }
194 const int xOffset = horizontalOffset();
195 const int yOffset = verticalOffset();
196 const QRectF visibleRect(xOffset, yOffset, viewport->width(), viewport->height());
197
198 QRect r = contentsRect.intersected(visibleRect).toAlignedRect();
199 if (r.isEmpty())
200 return;
201
202 r.translate(-xOffset, -yOffset);
203 viewport->update(r);
204}
205
207{
208 Q_Q(QTextEdit);
209 emit q->cursorPositionChanged();
210#if QT_CONFIG(accessibility)
211 QAccessibleTextCursorEvent event(q, q->textCursor().position());
212 QAccessible::updateAccessibility(&event);
213#endif
214}
215
216void QTextEditPrivate::hoveredBlockWithMarkerChanged(const QTextBlock &block)
217{
218#if QT_CONFIG(cursor)
219 Q_Q(QTextEdit);
220 Qt::CursorShape cursor = cursorToRestoreAfterHover;
221 if (block.isValid() && !q->isReadOnly()) {
222 QTextBlockFormat::MarkerType marker = block.blockFormat().marker();
223 if (marker != QTextBlockFormat::MarkerType::NoMarker) {
224 if (viewport->cursor().shape() != Qt::PointingHandCursor)
225 cursorToRestoreAfterHover = viewport->cursor().shape();
226 cursor = Qt::PointingHandCursor;
227 }
228 }
229 viewport->setCursor(cursor);
230#endif
231}
232
233void QTextEditPrivate::pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode)
234{
235 QTextCursor cursor = control->textCursor();
236 bool moved = false;
237 qreal lastY = control->cursorRect(cursor).top();
238 qreal distance = 0;
239 // move using movePosition to keep the cursor's x
240 do {
241 qreal y = control->cursorRect(cursor).top();
242 distance += qAbs(y - lastY);
243 lastY = y;
244 moved = cursor.movePosition(op, moveMode);
245 } while (moved && distance < viewport->height());
246
247 if (moved) {
248 if (op == QTextCursor::Up) {
249 cursor.movePosition(QTextCursor::Down, moveMode);
250 vbar->triggerAction(QAbstractSlider::SliderPageStepSub);
251 } else {
252 cursor.movePosition(QTextCursor::Up, moveMode);
253 vbar->triggerAction(QAbstractSlider::SliderPageStepAdd);
254 }
255 }
256 control->setTextCursor(cursor, moveMode == QTextCursor::KeepAnchor);
257}
258
259#if QT_CONFIG(scrollbar)
260static QSize documentSize(QWidgetTextControl *control)
261{
262 QTextDocument *doc = control->document();
263 QAbstractTextDocumentLayout *layout = doc->documentLayout();
264
265 QSize docSize;
266
267 if (QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout)) {
268 docSize = tlayout->dynamicDocumentSize().toSize();
269 int percentageDone = tlayout->layoutStatus();
270 // extrapolate height
271 if (percentageDone > 0)
272 docSize.setHeight(docSize.height() * 100 / percentageDone);
273 } else {
274 docSize = layout->documentSize().toSize();
275 }
276
277 return docSize;
278}
279
280void QTextEditPrivate::adjustScrollbars()
281{
282 if (ignoreAutomaticScrollbarAdjustment)
283 return;
284 ignoreAutomaticScrollbarAdjustment = true; // avoid recursion, #106108
285
286 QSize viewportSize = viewport->size();
287 QSize docSize = documentSize(control);
288
289 // due to the recursion guard we have to repeat this step a few times,
290 // as adding/removing a scroll bar will cause the document or viewport
291 // size to change
292 // ideally we should loop until the viewport size and doc size stabilize,
293 // but in corner cases they might fluctuate, so we need to limit the
294 // number of iterations
295 for (int i = 0; i < 4; ++i) {
296 hbar->setRange(0, docSize.width() - viewportSize.width());
297 hbar->setPageStep(viewportSize.width());
298
299 vbar->setRange(0, docSize.height() - viewportSize.height());
300 vbar->setPageStep(viewportSize.height());
301
302 // if we are in left-to-right mode widening the document due to
303 // lazy layouting does not require a repaint. If in right-to-left
304 // the scroll bar has the value zero and it visually has the maximum
305 // value (it is visually at the right), then widening the document
306 // keeps it at value zero but visually adjusts it to the new maximum
307 // on the right, hence we need an update.
308 if (q_func()->isRightToLeft())
309 viewport->update();
310
311 _q_showOrHideScrollBars();
312
313 const QSize oldViewportSize = viewportSize;
314 const QSize oldDocSize = docSize;
315
316 // make sure the document is layouted if the viewport width changes
317 viewportSize = viewport->size();
318 if (viewportSize.width() != oldViewportSize.width())
319 relayoutDocument();
320
321 docSize = documentSize(control);
322 if (viewportSize == oldViewportSize && docSize == oldDocSize)
323 break;
324 }
325 ignoreAutomaticScrollbarAdjustment = false;
326}
327#endif
328
329// rect is in content coordinates
330void QTextEditPrivate::ensureVisible(const QRectF &_rect)
331{
332 const QRect rect = _rect.toRect();
333 if ((vbar->isVisible() && vbar->maximum() < rect.bottom())
334 || (hbar->isVisible() && hbar->maximum() < rect.right()))
336 const int visibleWidth = viewport->width();
337 const int visibleHeight = viewport->height();
338 const bool rtl = q_func()->isRightToLeft();
339
340 if (rect.x() < horizontalOffset()) {
341 if (rtl)
342 hbar->setValue(hbar->maximum() - rect.x());
343 else
344 hbar->setValue(rect.x());
345 } else if (rect.x() + rect.width() > horizontalOffset() + visibleWidth) {
346 if (rtl)
347 hbar->setValue(hbar->maximum() - (rect.x() + rect.width() - visibleWidth));
348 else
349 hbar->setValue(rect.x() + rect.width() - visibleWidth);
350 }
351
352 if (rect.y() < verticalOffset())
353 vbar->setValue(rect.y());
354 else if (rect.y() + rect.height() > verticalOffset() + visibleHeight)
355 vbar->setValue(rect.y() + rect.height() - visibleHeight);
356}
357
358/*!
359 \class QTextEdit
360 \brief The QTextEdit class provides a widget that is used to edit and display
361 both plain and rich text.
362
363 \ingroup richtext-processing
364 \inmodule QtWidgets
365
366 \section1 Introduction and Concepts
367
368 QTextEdit is an advanced WYSIWYG viewer/editor supporting rich
369 text formatting using HTML-style tags, or Markdown format. It is optimized
370 to handle large documents and to respond quickly to user input.
371
372 QTextEdit works on paragraphs and characters. A paragraph is a
373 formatted string which is word-wrapped to fit into the width of
374 the widget. By default when reading plain text, one newline
375 signifies a paragraph. A document consists of zero or more
376 paragraphs. The words in the paragraph are aligned in accordance
377 with the paragraph's alignment. Paragraphs are separated by hard
378 line breaks. Each character within a paragraph has its own
379 attributes, for example, font and color.
380
381 QTextEdit can display images, lists and tables. If the text is
382 too large to view within the text edit's viewport, scroll bars will
383 appear. The text edit can load both plain text and rich text files.
384 Rich text can be described using a subset of HTML 4 markup; refer to the
385 \l {Supported HTML Subset} page for more information.
386
387 If you just need to display a small piece of rich text use QLabel.
388
389 The rich text support in Qt is designed to provide a fast, portable and
390 efficient way to add reasonable online help facilities to
391 applications, and to provide a basis for rich text editors. If
392 you find the HTML support insufficient for your needs you may consider
393 the use of Qt WebKit, which provides a full-featured web browser
394 widget.
395
396 The shape of the mouse cursor on a QTextEdit is Qt::IBeamCursor by default.
397 It can be changed through the viewport()'s cursor property.
398
399 \section1 Using QTextEdit as a Display Widget
400
401 QTextEdit can display a large HTML subset, including tables and
402 images.
403
404 The text can be set or replaced using \l setHtml() which deletes any
405 existing text and replaces it with the text passed in the
406 setHtml() call. If you call setHtml() with legacy HTML, and then
407 call toHtml(), the text that is returned may have different markup,
408 but will render the same. The entire text can be deleted with clear().
409
410 Text can also be set or replaced using \l setMarkdown(), and the same
411 caveats apply: if you then call \l toMarkdown(), the text that is returned
412 may be different, but the meaning is preserved as much as possible.
413 Markdown with some embedded HTML can be parsed, with the same limitations
414 that \l setHtml() has; but \l toMarkdown() only writes "pure" Markdown,
415 without any embedded HTML.
416
417 Text itself can be inserted using the QTextCursor class or using the
418 convenience functions insertHtml(), insertPlainText(), append() or
419 paste(). QTextCursor is also able to insert complex objects like tables
420 or lists into the document, and it deals with creating selections
421 and applying changes to selected text.
422
423 By default the text edit wraps words at whitespace to fit within
424 the text edit widget. The setLineWrapMode() function is used to
425 specify the kind of line wrap you want, or \l NoWrap if you don't
426 want any wrapping. Call setLineWrapMode() to set a fixed pixel width
427 \l FixedPixelWidth, or character column (e.g. 80 column) \l
428 FixedColumnWidth with the pixels or columns specified with
429 setLineWrapColumnOrWidth(). If you use word wrap to the widget's width
430 \l WidgetWidth, you can specify whether to break on whitespace or
431 anywhere with setWordWrapMode().
432
433 The find() function can be used to find and select a given string
434 within the text.
435
436 If you want to limit the total number of paragraphs in a QTextEdit,
437 as for example it is often useful in a log viewer, then you can use
438 QTextDocument's maximumBlockCount property for that.
439
440 \section2 Read-only Key Bindings
441
442 When QTextEdit is used read-only the key bindings are limited to
443 navigation, and text may only be selected with the mouse:
444 \table
445 \header \li Keypresses \li Action
446 \row \li Up \li Moves one line up.
447 \row \li Down \li Moves one line down.
448 \row \li Left \li Moves one character to the left.
449 \row \li Right \li Moves one character to the right.
450 \row \li PageUp \li Moves one (viewport) page up.
451 \row \li PageDown \li Moves one (viewport) page down.
452 \row \li Home \li Moves to the beginning of the text.
453 \row \li End \li Moves to the end of the text.
454 \row \li Alt+Wheel
455 \li Scrolls the page horizontally (the Wheel is the mouse wheel).
456 \row \li Ctrl+Wheel \li Zooms the text.
457 \row \li Ctrl+A \li Selects all text.
458 \endtable
459
460 The text edit may be able to provide some meta-information. For
461 example, the documentTitle() function will return the text from
462 within HTML \c{<title>} tags.
463
464 \note Zooming into HTML documents only works if the font-size is not set to a fixed size.
465
466 \section1 Using QTextEdit as an Editor
467
468 All the information about using QTextEdit as a display widget also
469 applies here.
470
471 The current char format's attributes are set with setFontItalic(),
472 setFontWeight(), setFontUnderline(), setFontFamily(),
473 setFontPointSize(), setTextColor() and setCurrentFont(). The current
474 paragraph's alignment is set with setAlignment().
475
476 Selection of text is handled by the QTextCursor class, which provides
477 functionality for creating selections, retrieving the text contents or
478 deleting selections. You can retrieve the object that corresponds with
479 the user-visible cursor using the textCursor() method. If you want to set
480 a selection in QTextEdit just create one on a QTextCursor object and
481 then make that cursor the visible cursor using setTextCursor(). The selection
482 can be copied to the clipboard with copy(), or cut to the clipboard with
483 cut(). The entire text can be selected using selectAll().
484
485 When the cursor is moved and the underlying formatting attributes change,
486 the currentCharFormatChanged() signal is emitted to reflect the new attributes
487 at the new cursor position.
488
489 The textChanged() signal is emitted whenever the text changes (as a result
490 of setText() or through the editor itself).
491
492 QTextEdit holds a QTextDocument object which can be retrieved using the
493 document() method. You can also set your own document object using setDocument().
494
495 QTextDocument provides an \l {QTextDocument::isModified()}{isModified()}
496 function which will return true if the text has been modified since it was
497 either loaded or since the last call to setModified with false as argument.
498 In addition it provides methods for undo and redo.
499
500 \section2 Drag and Drop
501
502 QTextEdit also supports custom drag and drop behavior. By default,
503 QTextEdit will insert plain text, HTML and rich text when the user drops
504 data of these MIME types onto a document. Reimplement
505 canInsertFromMimeData() and insertFromMimeData() to add support for
506 additional MIME types.
507
508 For example, to allow the user to drag and drop an image onto a QTextEdit,
509 you could the implement these functions in the following way:
510
511 \snippet textdocument-imagedrop/textedit.cpp 0
512
513 We add support for image MIME types by returning true. For all other
514 MIME types, we use the default implementation.
515
516 \snippet textdocument-imagedrop/textedit.cpp 1
517
518 We unpack the image from the QVariant held by the MIME source and insert
519 it into the document as a resource.
520
521 \section2 Editing Key Bindings
522
523 The list of key bindings which are implemented for editing:
524 \table
525 \header \li Keypresses \li Action
526 \row \li Backspace \li Deletes the character to the left of the cursor.
527 \row \li Delete \li Deletes the character to the right of the cursor.
528 \row \li Ctrl+C \li Copy the selected text to the clipboard.
529 \row \li Ctrl+Insert \li Copy the selected text to the clipboard.
530 \row \li Ctrl+K \li Deletes to the end of the line.
531 \row \li Ctrl+V \li Pastes the clipboard text into text edit.
532 \row \li Shift+Insert \li Pastes the clipboard text into text edit.
533 \row \li Ctrl+X \li Deletes the selected text and copies it to the clipboard.
534 \row \li Shift+Delete \li Deletes the selected text and copies it to the clipboard.
535 \row \li Ctrl+Z \li Undoes the last operation.
536 \row \li Ctrl+Y \li Redoes the last operation.
537 \row \li Left \li Moves the cursor one character to the left.
538 \row \li Ctrl+Left \li Moves the cursor one word to the left.
539 \row \li Right \li Moves the cursor one character to the right.
540 \row \li Ctrl+Right \li Moves the cursor one word to the right.
541 \row \li Up \li Moves the cursor one line up.
542 \row \li Down \li Moves the cursor one line down.
543 \row \li PageUp \li Moves the cursor one page up.
544 \row \li PageDown \li Moves the cursor one page down.
545 \row \li Home \li Moves the cursor to the beginning of the line.
546 \row \li Ctrl+Home \li Moves the cursor to the beginning of the text.
547 \row \li End \li Moves the cursor to the end of the line.
548 \row \li Ctrl+End \li Moves the cursor to the end of the text.
549 \row \li Alt+Wheel \li Scrolls the page horizontally (the Wheel is the mouse wheel).
550 \endtable
551
552 To select (mark) text hold down the Shift key whilst pressing one
553 of the movement keystrokes, for example, \e{Shift+Right}
554 will select the character to the right, and \e{Shift+Ctrl+Right} will select the word to the right, etc.
555
556 \sa QTextDocument, QTextCursor,
557 {Syntax Highlighter Example}, {Rich Text Processing}
558*/
559
560/*!
561 \property QTextEdit::plainText
562 \since 4.3
563
564 \brief the text editor's contents as plain text.
565
566 Previous contents are removed and undo/redo history is reset
567 when the property is set. currentCharFormat() is also reset, unless
568 textCursor() is already at the beginning of the document.
569
570 If the text edit has another content type, it will not be replaced
571 by plain text if you call toPlainText(). The only exception to this
572 is the non-break space, \e{nbsp;}, that will be converted into
573 standard space.
574
575 By default, for an editor with no contents, this property contains
576 an empty string.
577
578 \sa html
579*/
580
581/*!
582 \property QTextEdit::undoRedoEnabled
583 \brief whether undo and redo are enabled.
584
585 Users are only able to undo or redo actions if this property is
586 true, and if there is an action that can be undone (or redone).
587*/
588
589/*!
590 \enum QTextEdit::LineWrapMode
591
592 \value NoWrap
593 \value WidgetWidth
594 \value FixedPixelWidth
595 \value FixedColumnWidth
596*/
597
598/*!
599 \enum QTextEdit::AutoFormattingFlag
600
601 \value AutoNone Don't do any automatic formatting.
602 \value AutoBulletList Automatically create bullet lists (e.g. when
603 the user enters an asterisk ('*') in the left most column, or
604 presses Enter in an existing list item.
605 \value AutoAll Apply all automatic formatting. Currently only
606 automatic bullet lists are supported.
607*/
608
609
610/*!
611 Constructs an empty QTextEdit with parent \a
612 parent.
613*/
614QTextEdit::QTextEdit(QWidget *parent)
615 : QAbstractScrollArea(*new QTextEditPrivate, parent)
616{
617 Q_D(QTextEdit);
618 d->init();
619}
620
621/*!
622 \internal
623*/
624QTextEdit::QTextEdit(QTextEditPrivate &dd, QWidget *parent)
625 : QAbstractScrollArea(dd, parent)
626{
627 Q_D(QTextEdit);
628 d->init();
629}
630
631/*!
632 Constructs a QTextEdit with parent \a parent. The text edit will display
633 the text \a text. The text is interpreted as html.
634*/
635QTextEdit::QTextEdit(const QString &text, QWidget *parent)
636 : QAbstractScrollArea(*new QTextEditPrivate, parent)
637{
638 Q_D(QTextEdit);
639 d->init(text);
640}
641
642
643
644/*!
645 Destructor.
646*/
647QTextEdit::~QTextEdit()
648{
649}
650
651/*!
652 Returns the point size of the font of the current format.
653
654 \sa setFontFamily(), setCurrentFont(), setFontPointSize()
655*/
656qreal QTextEdit::fontPointSize() const
657{
658 Q_D(const QTextEdit);
659 return d->control->textCursor().charFormat().fontPointSize();
660}
661
662/*!
663 Returns the font family of the current format.
664
665 \sa setFontFamily(), setCurrentFont(), setFontPointSize()
666*/
667QString QTextEdit::fontFamily() const
668{
669 Q_D(const QTextEdit);
670 return d->control->textCursor().charFormat().fontFamilies().toStringList().value(0, QString());
671}
672
673/*!
674 Returns the font weight of the current format.
675
676 \sa setFontWeight(), setCurrentFont(), setFontPointSize(), QFont::Weight
677*/
678int QTextEdit::fontWeight() const
679{
680 Q_D(const QTextEdit);
681 return d->control->textCursor().charFormat().fontWeight();
682}
683
684/*!
685 Returns \c true if the font of the current format is underlined; otherwise returns
686 false.
687
688 \sa setFontUnderline()
689*/
690bool QTextEdit::fontUnderline() const
691{
692 Q_D(const QTextEdit);
693 return d->control->textCursor().charFormat().fontUnderline();
694}
695
696/*!
697 Returns \c true if the font of the current format is italic; otherwise returns
698 false.
699
700 \sa setFontItalic()
701*/
702bool QTextEdit::fontItalic() const
703{
704 Q_D(const QTextEdit);
705 return d->control->textCursor().charFormat().fontItalic();
706}
707
708/*!
709 Returns the text color of the current format.
710
711 \sa setTextColor()
712*/
713QColor QTextEdit::textColor() const
714{
715 Q_D(const QTextEdit);
716
717 const auto fg = d->control->textCursor().charFormat().foreground();
718 if (fg.style() == Qt::NoBrush) {
719 const auto context = d->control->getPaintContext(const_cast<QTextEdit *>(this));
720 return context.palette.color(QPalette::Text);
721 }
722
723 return fg.color();
724}
725
726/*!
727 \since 4.4
728
729 Returns the text background color of the current format.
730
731 \sa setTextBackgroundColor()
732*/
733QColor QTextEdit::textBackgroundColor() const
734{
735 Q_D(const QTextEdit);
736 const QBrush &brush = d->control->textCursor().charFormat().background();
737 return brush.style() == Qt::NoBrush ? Qt::transparent : brush.color();
738}
739
740/*!
741 Returns the font of the current format.
742
743 \sa setCurrentFont(), setFontFamily(), setFontPointSize()
744*/
745QFont QTextEdit::currentFont() const
746{
747 Q_D(const QTextEdit);
748 return d->control->textCursor().charFormat().font();
749}
750
751/*!
752 Sets the alignment of the current paragraph to \a a. Valid
753 alignments are Qt::AlignLeft, Qt::AlignRight,
754 Qt::AlignJustify and Qt::AlignCenter (which centers
755 horizontally).
756*/
757void QTextEdit::setAlignment(Qt::Alignment a)
758{
759 Q_D(QTextEdit);
760 QTextBlockFormat fmt;
761 fmt.setAlignment(a);
762 QTextCursor cursor = d->control->textCursor();
763 cursor.mergeBlockFormat(fmt);
764 d->control->setTextCursor(cursor);
765 d->relayoutDocument();
766}
767
768/*!
769 Returns the alignment of the current paragraph.
770
771 \sa setAlignment()
772*/
773Qt::Alignment QTextEdit::alignment() const
774{
775 Q_D(const QTextEdit);
776 return d->control->textCursor().blockFormat().alignment();
777}
778
779/*!
780 \property QTextEdit::document
781 \brief the underlying document of the text editor.
782
783 \note The editor \e{does not take ownership of the document} unless it
784 is the document's parent object. The parent object of the provided document
785 remains the owner of the object. If the previously assigned document is a
786 child of the editor then it will be deleted.
787*/
788void QTextEdit::setDocument(QTextDocument *document)
789{
790 Q_D(QTextEdit);
791 d->control->setDocument(document);
792 d->updateDefaultTextOption();
793 d->relayoutDocument();
794}
795
796QTextDocument *QTextEdit::document() const
797{
798 Q_D(const QTextEdit);
799 return d->control->document();
800}
801
802/*!
803 \since 5.2
804
805 \property QTextEdit::placeholderText
806 \brief the editor placeholder text
807
808 Setting this property makes the editor display a grayed-out
809 placeholder text as long as the document() is empty.
810
811 By default, this property contains an empty string.
812
813 \sa document()
814*/
815QString QTextEdit::placeholderText() const
816{
817 Q_D(const QTextEdit);
818 return d->placeholderText;
819}
820
821void QTextEdit::setPlaceholderText(const QString &placeholderText)
822{
823 Q_D(QTextEdit);
824 if (d->placeholderText != placeholderText) {
825 d->placeholderText = placeholderText;
826 if (d->control->document()->isEmpty())
827 d->viewport->update();
828 }
829}
830
831/*!
832 Sets the visible \a cursor.
833*/
834void QTextEdit::setTextCursor(const QTextCursor &cursor)
835{
836 doSetTextCursor(cursor);
837}
838
839/*!
840 \internal
841
842 This provides a hook for subclasses to intercept cursor changes.
843*/
844
845void QTextEdit::doSetTextCursor(const QTextCursor &cursor)
846{
847 Q_D(QTextEdit);
848 d->control->setTextCursor(cursor);
849}
850
851/*!
852 Returns a copy of the QTextCursor that represents the currently visible cursor.
853 Note that changes on the returned cursor do not affect QTextEdit's cursor; use
854 setTextCursor() to update the visible cursor.
855 */
856QTextCursor QTextEdit::textCursor() const
857{
858 Q_D(const QTextEdit);
859 return d->control->textCursor();
860}
861
862/*!
863 Sets the font family of the current format to \a fontFamily.
864
865 \sa fontFamily(), setCurrentFont()
866*/
867void QTextEdit::setFontFamily(const QString &fontFamily)
868{
869 QTextCharFormat fmt;
870 fmt.setFontFamilies({fontFamily});
871 mergeCurrentCharFormat(fmt);
872}
873
874/*!
875 Sets the point size of the current format to \a s.
876
877 Note that if \a s is zero or negative, the behavior of this
878 function is not defined.
879
880 \sa fontPointSize(), setCurrentFont(), setFontFamily()
881*/
882void QTextEdit::setFontPointSize(qreal s)
883{
884 QTextCharFormat fmt;
885 fmt.setFontPointSize(s);
886 mergeCurrentCharFormat(fmt);
887}
888
889/*!
890 \fn void QTextEdit::setFontWeight(int weight)
891
892 Sets the font weight of the current format to the given \a weight,
893 where the value used is in the range defined by the QFont::Weight
894 enum.
895
896 \sa fontWeight(), setCurrentFont(), setFontFamily()
897*/
898void QTextEdit::setFontWeight(int w)
899{
900 QTextCharFormat fmt;
901 fmt.setFontWeight(w);
902 mergeCurrentCharFormat(fmt);
903}
904
905/*!
906 If \a underline is true, sets the current format to underline;
907 otherwise sets the current format to non-underline.
908
909 \sa fontUnderline()
910*/
911void QTextEdit::setFontUnderline(bool underline)
912{
913 QTextCharFormat fmt;
914 fmt.setFontUnderline(underline);
915 mergeCurrentCharFormat(fmt);
916}
917
918/*!
919 If \a italic is true, sets the current format to italic;
920 otherwise sets the current format to non-italic.
921
922 \sa fontItalic()
923*/
924void QTextEdit::setFontItalic(bool italic)
925{
926 QTextCharFormat fmt;
927 fmt.setFontItalic(italic);
928 mergeCurrentCharFormat(fmt);
929}
930
931/*!
932 Sets the text color of the current format to \a c.
933
934 \sa textColor()
935*/
936void QTextEdit::setTextColor(const QColor &c)
937{
938 QTextCharFormat fmt;
939 fmt.setForeground(QBrush(c));
940 mergeCurrentCharFormat(fmt);
941}
942
943/*!
944 \since 4.4
945
946 Sets the text background color of the current format to \a c.
947
948 \sa textBackgroundColor()
949*/
950void QTextEdit::setTextBackgroundColor(const QColor &c)
951{
952 QTextCharFormat fmt;
953 fmt.setBackground(QBrush(c));
954 mergeCurrentCharFormat(fmt);
955}
956
957/*!
958 Sets the font of the current format to \a f.
959
960 \sa currentFont(), setFontPointSize(), setFontFamily()
961*/
962void QTextEdit::setCurrentFont(const QFont &f)
963{
964 QTextCharFormat fmt;
965 fmt.setFont(f);
966 mergeCurrentCharFormat(fmt);
967}
968
969/*!
970 \since 4.2
971
972 Undoes the last operation.
973
974 If there is no operation to undo, i.e. there is no undo step in
975 the undo/redo history, nothing happens.
976
977 \sa redo()
978*/
979void QTextEdit::undo()
980{
981 Q_D(QTextEdit);
982 d->control->undo();
983}
984
985void QTextEdit::redo()
986{
987 Q_D(QTextEdit);
988 d->control->redo();
989}
990
991/*!
992 \fn void QTextEdit::redo()
993 \since 4.2
994
995 Redoes the last operation.
996
997 If there is no operation to redo, i.e. there is no redo step in
998 the undo/redo history, nothing happens.
999
1000 \sa undo()
1001*/
1002
1003#ifndef QT_NO_CLIPBOARD
1004/*!
1005 Copies the selected text to the clipboard and deletes it from
1006 the text edit.
1007
1008 If there is no selected text nothing happens.
1009
1010 \sa copy(), paste()
1011*/
1012
1013void QTextEdit::cut()
1014{
1015 Q_D(QTextEdit);
1016 d->control->cut();
1017}
1018
1019/*!
1020 Copies any selected text to the clipboard.
1021
1022 \sa copyAvailable()
1023*/
1024
1025void QTextEdit::copy()
1026{
1027 Q_D(QTextEdit);
1028 d->control->copy();
1029}
1030
1031/*!
1032 Pastes the text from the clipboard into the text edit at the
1033 current cursor position.
1034
1035 If there is no text in the clipboard nothing happens.
1036
1037 To change the behavior of this function, i.e. to modify what
1038 QTextEdit can paste and how it is being pasted, reimplement the
1039 virtual canInsertFromMimeData() and insertFromMimeData()
1040 functions.
1041
1042 \sa cut(), copy()
1043*/
1044
1045void QTextEdit::paste()
1046{
1047 Q_D(QTextEdit);
1048 d->control->paste();
1049}
1050#endif
1051
1052/*!
1053 Deletes all the text in the text edit.
1054
1055 Notes:
1056 \list
1057 \li The undo/redo history is also cleared.
1058 \li currentCharFormat() is reset, unless textCursor()
1059 is already at the beginning of the document.
1060 \endlist
1061
1062 \sa cut(), setPlainText(), setHtml()
1063*/
1064void QTextEdit::clear()
1065{
1066 Q_D(QTextEdit);
1067 // clears and sets empty content
1068 d->control->clear();
1069}
1070
1071
1072/*!
1073 Selects all text.
1074
1075 \sa copy(), cut(), textCursor()
1076 */
1077void QTextEdit::selectAll()
1078{
1079 Q_D(QTextEdit);
1080 d->control->selectAll();
1081}
1082
1083/*! \internal
1084*/
1085bool QTextEdit::event(QEvent *e)
1086{
1087 Q_D(QTextEdit);
1088 switch (e->type()) {
1089 case QEvent::ShortcutOverride:
1090 case QEvent::ToolTip:
1091 d->sendControlEvent(e);
1092 break;
1093 case QEvent::WindowActivate:
1094 case QEvent::WindowDeactivate:
1095 d->control->setPalette(palette());
1096 break;
1097#ifndef QT_NO_CONTEXTMENU
1098 case QEvent::ContextMenu:
1099 if (static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard) {
1100 ensureCursorVisible();
1101 const QPoint cursorPos = cursorRect().center();
1102 QContextMenuEvent ce(QContextMenuEvent::Keyboard, cursorPos, d->viewport->mapToGlobal(cursorPos));
1103 ce.setAccepted(e->isAccepted());
1104 const bool result = QAbstractScrollArea::event(&ce);
1105 e->setAccepted(ce.isAccepted());
1106 return result;
1107 }
1108 break;
1109#endif // QT_NO_CONTEXTMENU
1110#ifdef QT_KEYPAD_NAVIGATION
1111 case QEvent::EnterEditFocus:
1112 case QEvent::LeaveEditFocus:
1113 if (QApplicationPrivate::keypadNavigationEnabled())
1114 d->sendControlEvent(e);
1115 break;
1116#endif
1117 default:
1118 break;
1119 }
1120 return QAbstractScrollArea::event(e);
1121}
1122
1123/*! \internal
1124*/
1125
1126void QTextEdit::timerEvent(QTimerEvent *e)
1127{
1128 Q_D(QTextEdit);
1129 if (e->timerId() == d->autoScrollTimer.timerId()) {
1130 QRect visible = d->viewport->rect();
1131 QPoint pos;
1132 if (d->inDrag) {
1133 pos = d->autoScrollDragPos;
1134 visible.adjust(qMin(visible.width()/3,20), qMin(visible.height()/3,20),
1135 -qMin(visible.width()/3,20), -qMin(visible.height()/3,20));
1136 } else {
1137 const QPoint globalPos = QCursor::pos();
1138 pos = d->viewport->mapFromGlobal(globalPos);
1139 QMouseEvent ev(QEvent::MouseMove, pos, mapTo(topLevelWidget(), pos), globalPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
1140 mouseMoveEvent(&ev);
1141 }
1142 int deltaY = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();
1143 int deltaX = qMax(pos.x() - visible.left(), visible.right() - pos.x()) - visible.width();
1144 int delta = qMax(deltaX, deltaY);
1145 if (delta >= 0) {
1146 if (delta < 7)
1147 delta = 7;
1148 int timeout = 4900 / (delta * delta);
1149 d->autoScrollTimer.start(timeout, this);
1150
1151 if (deltaY > 0)
1152 d->vbar->triggerAction(pos.y() < visible.center().y() ?
1153 QAbstractSlider::SliderSingleStepSub
1154 : QAbstractSlider::SliderSingleStepAdd);
1155 if (deltaX > 0)
1156 d->hbar->triggerAction(pos.x() < visible.center().x() ?
1157 QAbstractSlider::SliderSingleStepSub
1158 : QAbstractSlider::SliderSingleStepAdd);
1159 }
1160 }
1161#ifdef QT_KEYPAD_NAVIGATION
1162 else if (e->timerId() == d->deleteAllTimer.timerId()) {
1163 d->deleteAllTimer.stop();
1164 clear();
1165 }
1166#endif
1167}
1168
1169/*!
1170 Changes the text of the text edit to the string \a text.
1171 Any previous text is removed.
1172
1173 Notes:
1174 \list
1175 \li \a text is interpreted as plain text.
1176 \li The undo/redo history is also cleared.
1177 \li currentCharFormat() is reset, unless textCursor()
1178 is already at the beginning of the document.
1179 \endlist
1180
1181 \sa toPlainText()
1182*/
1183
1184void QTextEdit::setPlainText(const QString &text)
1185{
1186 Q_D(QTextEdit);
1187 d->control->setPlainText(text);
1188 d->preferRichText = false;
1189}
1190
1191/*!
1192 QString QTextEdit::toPlainText() const
1193
1194 Returns the text of the text edit as plain text.
1195
1196 \sa QTextEdit::setPlainText()
1197 */
1198QString QTextEdit::toPlainText() const
1199{
1200 Q_D(const QTextEdit);
1201 return d->control->toPlainText();
1202}
1203
1204/*!
1205 \property QTextEdit::html
1206
1207 This property provides an HTML interface to the text of the text edit.
1208
1209 toHtml() returns the text of the text edit as html.
1210
1211 setHtml() changes the text of the text edit. Any previous text is
1212 removed and the undo/redo history is cleared. The input text is
1213 interpreted as rich text in html format. currentCharFormat() is also
1214 reset, unless textCursor() is already at the beginning of the document.
1215
1216 \note It is the responsibility of the caller to make sure that the
1217 text is correctly decoded when a QString containing HTML is created
1218 and passed to setHtml().
1219
1220 By default, for a newly-created, empty document, this property contains
1221 text to describe an HTML 4.0 document with no body text.
1222
1223 \sa {Supported HTML Subset}, plainText
1224*/
1225
1226#ifndef QT_NO_TEXTHTMLPARSER
1227void QTextEdit::setHtml(const QString &text)
1228{
1229 Q_D(QTextEdit);
1230 d->control->setHtml(text);
1231 d->preferRichText = true;
1232}
1233
1234QString QTextEdit::toHtml() const
1235{
1236 Q_D(const QTextEdit);
1237 return d->control->toHtml();
1238}
1239#endif
1240
1241#if QT_CONFIG(textmarkdownreader) && QT_CONFIG(textmarkdownwriter)
1242/*!
1243 \property QTextEdit::markdown
1244
1245 This property provides a Markdown interface to the text of the text edit.
1246
1247 \c toMarkdown() returns the text of the text edit as "pure" Markdown,
1248 without any embedded HTML formatting. Some features that QTextDocument
1249 supports (such as the use of specific colors and named fonts) cannot be
1250 expressed in "pure" Markdown, and they will be omitted.
1251
1252 \c setMarkdown() changes the text of the text edit. Any previous text is
1253 removed and the undo/redo history is cleared. The input text is
1254 interpreted as rich text in Markdown format.
1255
1256 Parsing of HTML included in the \a markdown string is handled in the same
1257 way as in \l setHtml; however, Markdown formatting inside HTML blocks is
1258 not supported.
1259
1260 Some features of the parser can be enabled or disabled via the \a features
1261 argument:
1262
1263 \value MarkdownNoHTML
1264 Any HTML tags in the Markdown text will be discarded
1265 \value MarkdownDialectCommonMark
1266 The parser supports only the features standardized by CommonMark
1267 \value MarkdownDialectGitHub
1268 The parser supports the GitHub dialect
1269
1270 The default is \c MarkdownDialectGitHub.
1271
1272 \sa plainText, html, QTextDocument::toMarkdown(), QTextDocument::setMarkdown()
1273 \since 5.14
1274*/
1275#endif
1276
1277#if QT_CONFIG(textmarkdownreader)
1278void QTextEdit::setMarkdown(const QString &markdown)
1279{
1280 Q_D(const QTextEdit);
1281 d->control->setMarkdown(markdown);
1282}
1283#endif
1284
1285#if QT_CONFIG(textmarkdownwriter)
1286QString QTextEdit::toMarkdown(QTextDocument::MarkdownFeatures features) const
1287{
1288 Q_D(const QTextEdit);
1289 return d->control->toMarkdown(features);
1290}
1291#endif
1292
1293/*! \reimp
1294*/
1295void QTextEdit::keyPressEvent(QKeyEvent *e)
1296{
1297 Q_D(QTextEdit);
1298
1299#ifdef QT_KEYPAD_NAVIGATION
1300 switch (e->key()) {
1301 case Qt::Key_Select:
1302 if (QApplicationPrivate::keypadNavigationEnabled()) {
1303 // code assumes linksaccessible + editable isn't meaningful
1304 if (d->control->textInteractionFlags() & Qt::TextEditable) {
1305 setEditFocus(!hasEditFocus());
1306 } else {
1307 if (!hasEditFocus())
1308 setEditFocus(true);
1309 else {
1310 QTextCursor cursor = d->control->textCursor();
1311 QTextCharFormat charFmt = cursor.charFormat();
1312 if (!(d->control->textInteractionFlags() & Qt::LinksAccessibleByKeyboard)
1313 || !cursor.hasSelection() || charFmt.anchorHref().isEmpty()) {
1314 e->accept();
1315 return;
1316 }
1317 }
1318 }
1319 }
1320 break;
1321 case Qt::Key_Back:
1322 case Qt::Key_No:
1323 if (!QApplicationPrivate::keypadNavigationEnabled() || !hasEditFocus()) {
1324 e->ignore();
1325 return;
1326 }
1327 break;
1328 default:
1329 if (QApplicationPrivate::keypadNavigationEnabled()) {
1330 if (!hasEditFocus() && !(e->modifiers() & Qt::ControlModifier)) {
1331 if (e->text()[0].isPrint())
1332 setEditFocus(true);
1333 else {
1334 e->ignore();
1335 return;
1336 }
1337 }
1338 }
1339 break;
1340 }
1341#endif
1342#ifndef QT_NO_SHORTCUT
1343
1344 Qt::TextInteractionFlags tif = d->control->textInteractionFlags();
1345
1346 if (tif & Qt::TextSelectableByKeyboard){
1347 if (e == QKeySequence::SelectPreviousPage) {
1348 e->accept();
1349 d->pageUpDown(QTextCursor::Up, QTextCursor::KeepAnchor);
1350 return;
1351 } else if (e ==QKeySequence::SelectNextPage) {
1352 e->accept();
1353 d->pageUpDown(QTextCursor::Down, QTextCursor::KeepAnchor);
1354 return;
1355 }
1356 }
1357 if (tif & (Qt::TextSelectableByKeyboard | Qt::TextEditable)) {
1358 if (e == QKeySequence::MoveToPreviousPage) {
1359 e->accept();
1360 d->pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor);
1361 return;
1362 } else if (e == QKeySequence::MoveToNextPage) {
1363 e->accept();
1364 d->pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor);
1365 return;
1366 }
1367 }
1368
1369 if (!(tif & Qt::TextEditable)) {
1370 switch (e->key()) {
1371 case Qt::Key_Space:
1372 e->accept();
1373 if (e->modifiers() & Qt::ShiftModifier)
1374 d->vbar->triggerAction(QAbstractSlider::SliderPageStepSub);
1375 else
1376 d->vbar->triggerAction(QAbstractSlider::SliderPageStepAdd);
1377 break;
1378 default:
1379 d->sendControlEvent(e);
1380 if (!e->isAccepted() && e->modifiers() == Qt::NoModifier) {
1381 if (e->key() == Qt::Key_Home) {
1382 d->vbar->triggerAction(QAbstractSlider::SliderToMinimum);
1383 e->accept();
1384 } else if (e->key() == Qt::Key_End) {
1385 d->vbar->triggerAction(QAbstractSlider::SliderToMaximum);
1386 e->accept();
1387 }
1388 }
1389 if (!e->isAccepted()) {
1390 QAbstractScrollArea::keyPressEvent(e);
1391 }
1392 }
1393 return;
1394 }
1395#endif // QT_NO_SHORTCUT
1396
1397 {
1398 QTextCursor cursor = d->control->textCursor();
1399 const QString text = e->text();
1400 if (cursor.atBlockStart()
1401 && (d->autoFormatting & AutoBulletList)
1402 && (text.size() == 1)
1403 && (text.at(0) == u'-' || text.at(0) == u'*')
1404 && (!cursor.currentList())) {
1405
1406 d->createAutoBulletList();
1407 e->accept();
1408 return;
1409 }
1410 }
1411
1412 d->sendControlEvent(e);
1413#ifdef QT_KEYPAD_NAVIGATION
1414 if (!e->isAccepted()) {
1415 switch (e->key()) {
1416 case Qt::Key_Up:
1417 case Qt::Key_Down:
1418 if (QApplicationPrivate::keypadNavigationEnabled()) {
1419 // Cursor position didn't change, so we want to leave
1420 // these keys to change focus.
1421 e->ignore();
1422 return;
1423 }
1424 break;
1425 case Qt::Key_Back:
1426 if (!e->isAutoRepeat()) {
1427 if (QApplicationPrivate::keypadNavigationEnabled()) {
1428 if (document()->isEmpty() || !(d->control->textInteractionFlags() & Qt::TextEditable)) {
1429 setEditFocus(false);
1430 e->accept();
1431 } else if (!d->deleteAllTimer.isActive()) {
1432 e->accept();
1433 d->deleteAllTimer.start(750, this);
1434 }
1435 } else {
1436 e->ignore();
1437 return;
1438 }
1439 }
1440 break;
1441 default: break;
1442 }
1443 }
1444#endif
1445}
1446
1447/*! \reimp
1448*/
1449void QTextEdit::keyReleaseEvent(QKeyEvent *e)
1450{
1451 Q_D(QTextEdit);
1452 if (!isReadOnly())
1453 d->handleSoftwareInputPanel();
1454#ifdef QT_KEYPAD_NAVIGATION
1455 if (QApplicationPrivate::keypadNavigationEnabled()) {
1456 if (!e->isAutoRepeat() && e->key() == Qt::Key_Back
1457 && d->deleteAllTimer.isActive()) {
1458 d->deleteAllTimer.stop();
1459 QTextCursor cursor = d->control->textCursor();
1460 QTextBlockFormat blockFmt = cursor.blockFormat();
1461
1462 QTextList *list = cursor.currentList();
1463 if (list && cursor.atBlockStart()) {
1464 list->remove(cursor.block());
1465 } else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
1466 blockFmt.setIndent(blockFmt.indent() - 1);
1467 cursor.setBlockFormat(blockFmt);
1468 } else {
1469 cursor.deletePreviousChar();
1470 }
1471 setTextCursor(cursor);
1472 e->accept();
1473 return;
1474 }
1475 }
1476#endif
1477 e->ignore();
1478}
1479
1480/*!
1481 Loads the resource specified by the given \a type and \a name.
1482
1483 This function is an extension of QTextDocument::loadResource().
1484
1485 \sa QTextDocument::loadResource()
1486*/
1487QVariant QTextEdit::loadResource(int type, const QUrl &name)
1488{
1489 Q_UNUSED(type);
1490 Q_UNUSED(name);
1491 return QVariant();
1492}
1493
1494/*! \reimp
1495*/
1496void QTextEdit::resizeEvent(QResizeEvent *e)
1497{
1498 Q_D(QTextEdit);
1499
1500 if (d->lineWrap == NoWrap) {
1501 QTextDocument *doc = d->control->document();
1502 QVariant alignmentProperty = doc->documentLayout()->property("contentHasAlignment");
1503
1504 if (!doc->pageSize().isNull()
1505 && alignmentProperty.userType() == QMetaType::Bool
1506 && !alignmentProperty.toBool()) {
1507
1508 d->adjustScrollbars();
1509 return;
1510 }
1511 }
1512
1513 if (d->lineWrap != FixedPixelWidth
1514 && e->oldSize().width() != e->size().width())
1515 d->relayoutDocument();
1516 else
1517 d->adjustScrollbars();
1518}
1519
1521{
1522 QTextDocument *doc = control->document();
1523 QAbstractTextDocumentLayout *layout = doc->documentLayout();
1524
1525 if (QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout)) {
1526 if (lineWrap == QTextEdit::FixedColumnWidth)
1527 tlayout->setFixedColumnWidth(lineWrapColumnOrWidth);
1528 else
1529 tlayout->setFixedColumnWidth(-1);
1530 }
1531
1532 QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout);
1533 QSize lastUsedSize;
1534 if (tlayout)
1535 lastUsedSize = tlayout->dynamicDocumentSize().toSize();
1536 else
1537 lastUsedSize = layout->documentSize().toSize();
1538
1539 // ignore calls to adjustScrollbars caused by an emission of the
1540 // usedSizeChanged() signal in the layout, as we're calling it
1541 // later on our own anyway (or deliberately not) .
1542 const bool oldIgnoreScrollbarAdjustment = ignoreAutomaticScrollbarAdjustment;
1543 ignoreAutomaticScrollbarAdjustment = true;
1544
1545 int width = viewport->width();
1546 if (lineWrap == QTextEdit::FixedPixelWidth)
1547 width = lineWrapColumnOrWidth;
1548 else if (lineWrap == QTextEdit::NoWrap) {
1549 QVariant alignmentProperty = doc->documentLayout()->property("contentHasAlignment");
1550 if (alignmentProperty.userType() == QMetaType::Bool && !alignmentProperty.toBool()) {
1551
1552 width = 0;
1553 }
1554 }
1555
1556 doc->setPageSize(QSize(width, -1));
1557 if (tlayout)
1558 tlayout->ensureLayouted(verticalOffset() + viewport->height());
1559
1560 ignoreAutomaticScrollbarAdjustment = oldIgnoreScrollbarAdjustment;
1561
1562 QSize usedSize;
1563 if (tlayout)
1564 usedSize = tlayout->dynamicDocumentSize().toSize();
1565 else
1566 usedSize = layout->documentSize().toSize();
1567
1568 // this is an obscure situation in the layout that can happen:
1569 // if a character at the end of a line is the tallest one and therefore
1570 // influencing the total height of the line and the line right below it
1571 // is always taller though, then it can happen that if due to line breaking
1572 // that tall character wraps into the lower line the document not only shrinks
1573 // horizontally (causing the character to wrap in the first place) but also
1574 // vertically, because the original line is now smaller and the one below kept
1575 // its size. So a layout with less width _can_ take up less vertical space, too.
1576 // If the wider case causes a vertical scroll bar to appear and the narrower one
1577 // (narrower because the vertical scroll bar takes up horizontal space)) to disappear
1578 // again then we have an endless loop, as adjustScrollbars sets new ranges on the
1579 // scroll bars, the QAbstractScrollArea will find out about it and try to show/hide
1580 // the scroll bars again. That's why we try to detect this case here and break out.
1581 //
1582 // (if you change this please also check the layoutingLoop() testcase in
1583 // QTextEdit's autotests)
1584 if (lastUsedSize.isValid()
1585 && !vbar->isHidden()
1586 && viewport->width() < lastUsedSize.width()
1587 && usedSize.height() < lastUsedSize.height()
1588 && usedSize.height() <= viewport->height())
1589 return;
1590
1592}
1593
1594void QTextEditPrivate::paint(QPainter *p, QPaintEvent *e)
1595{
1596 const int xOffset = horizontalOffset();
1597 const int yOffset = verticalOffset();
1598
1599 QRect r = e->rect();
1600 p->translate(-xOffset, -yOffset);
1601 r.translate(xOffset, yOffset);
1602
1603 QTextDocument *doc = control->document();
1604 QTextDocumentLayout *layout = qobject_cast<QTextDocumentLayout *>(doc->documentLayout());
1605
1606 // the layout might need to expand the root frame to
1607 // the viewport if NoWrap is set
1608 if (layout)
1609 layout->setViewport(viewport->rect());
1610
1611 control->drawContents(p, r, q_func());
1612
1613 if (layout)
1614 layout->setViewport(QRect());
1615
1616 if (!placeholderText.isEmpty() && doc->isEmpty() && !control->isPreediting()) {
1617 const QColor col = control->palette().placeholderText().color();
1618 p->setPen(col);
1619 const int margin = int(doc->documentMargin());
1620 QRectF boundingRect = layout ? layout->frameBoundingRect(doc->rootFrame()) : viewport->rect();
1621 p->drawText(boundingRect.adjusted(margin, margin, -margin, -margin),
1622 Qt::AlignTop | Qt::TextWordWrap,
1623 placeholderText);
1624 }
1625}
1626
1627/*! \fn void QTextEdit::paintEvent(QPaintEvent *event)
1628
1629This event handler can be reimplemented in a subclass to receive paint events passed in \a event.
1630It is usually unnecessary to reimplement this function in a subclass of QTextEdit.
1631
1632\note If you create a QPainter, it must operate on the \l{QAbstractScrollArea::}{viewport()}.
1633
1634\warning The underlying text document must not be modified from within a reimplementation
1635of this function.
1636*/
1637void QTextEdit::paintEvent(QPaintEvent *e)
1638{
1639 Q_D(QTextEdit);
1640 QPainter p(d->viewport);
1641 d->paint(&p, e);
1642}
1643
1645{
1646 QTextDocument *doc = control->document();
1647
1648 QTextOption opt = doc->defaultTextOption();
1649 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1650
1651 if (lineWrap == QTextEdit::NoWrap)
1652 opt.setWrapMode(QTextOption::NoWrap);
1653 else
1654 opt.setWrapMode(wordWrap);
1655
1656 if (opt.wrapMode() != oldWrapMode)
1657 doc->setDefaultTextOption(opt);
1658}
1659
1660/*! \reimp
1661*/
1662void QTextEdit::mousePressEvent(QMouseEvent *e)
1663{
1664 Q_D(QTextEdit);
1665#ifdef QT_KEYPAD_NAVIGATION
1666 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus())
1667 setEditFocus(true);
1668#endif
1669 d->sendControlEvent(e);
1670}
1671
1672/*! \reimp
1673*/
1674void QTextEdit::mouseMoveEvent(QMouseEvent *e)
1675{
1676 Q_D(QTextEdit);
1677 d->inDrag = false; // paranoia
1678 const QPoint pos = e->position().toPoint();
1679 d->sendControlEvent(e);
1680 if (!(e->buttons() & Qt::LeftButton))
1681 return;
1682 if (e->source() == Qt::MouseEventNotSynthesized) {
1683 const QRect visible = d->viewport->rect();
1684 if (visible.contains(pos))
1685 d->autoScrollTimer.stop();
1686 else if (!d->autoScrollTimer.isActive())
1687 d->autoScrollTimer.start(100, this);
1688 }
1689}
1690
1691/*! \reimp
1692*/
1693void QTextEdit::mouseReleaseEvent(QMouseEvent *e)
1694{
1695 Q_D(QTextEdit);
1696 d->sendControlEvent(e);
1697 if (e->source() == Qt::MouseEventNotSynthesized && d->autoScrollTimer.isActive()) {
1698 d->autoScrollTimer.stop();
1699 ensureCursorVisible();
1700 }
1701 if (!isReadOnly() && rect().contains(e->position().toPoint()))
1702 d->handleSoftwareInputPanel(e->button(), d->clickCausedFocus);
1703 d->clickCausedFocus = 0;
1704}
1705
1706/*! \reimp
1707*/
1708void QTextEdit::mouseDoubleClickEvent(QMouseEvent *e)
1709{
1710 Q_D(QTextEdit);
1711 d->sendControlEvent(e);
1712}
1713
1714/*! \reimp
1715*/
1716bool QTextEdit::focusNextPrevChild(bool next)
1717{
1718 Q_D(const QTextEdit);
1719 if (!d->tabChangesFocus && d->control->textInteractionFlags() & Qt::TextEditable)
1720 return false;
1721 return QAbstractScrollArea::focusNextPrevChild(next);
1722}
1723
1724#ifndef QT_NO_CONTEXTMENU
1725/*!
1726 \fn void QTextEdit::contextMenuEvent(QContextMenuEvent *event)
1727
1728 Shows the standard context menu created with createStandardContextMenu().
1729
1730 If you do not want the text edit to have a context menu, you can set
1731 its \l contextMenuPolicy to Qt::NoContextMenu. If you want to
1732 customize the context menu, reimplement this function. If you want
1733 to extend the standard context menu, reimplement this function, call
1734 createStandardContextMenu() and extend the menu returned.
1735
1736 Information about the event is passed in the \a event object.
1737
1738 \snippet code/src_gui_widgets_qtextedit.cpp 0
1739*/
1740void QTextEdit::contextMenuEvent(QContextMenuEvent *e)
1741{
1742 Q_D(QTextEdit);
1743 d->sendControlEvent(e);
1744}
1745#endif // QT_NO_CONTEXTMENU
1746
1747#if QT_CONFIG(draganddrop)
1748/*! \reimp
1749*/
1750void QTextEdit::dragEnterEvent(QDragEnterEvent *e)
1751{
1752 Q_D(QTextEdit);
1753 d->inDrag = true;
1754 d->sendControlEvent(e);
1755}
1756
1757/*! \reimp
1758*/
1759void QTextEdit::dragLeaveEvent(QDragLeaveEvent *e)
1760{
1761 Q_D(QTextEdit);
1762 d->inDrag = false;
1763 d->autoScrollTimer.stop();
1764 d->sendControlEvent(e);
1765}
1766
1767/*! \reimp
1768*/
1769void QTextEdit::dragMoveEvent(QDragMoveEvent *e)
1770{
1771 Q_D(QTextEdit);
1772 d->autoScrollDragPos = e->position().toPoint();
1773 if (!d->autoScrollTimer.isActive())
1774 d->autoScrollTimer.start(100, this);
1775 d->sendControlEvent(e);
1776}
1777
1778/*! \reimp
1779*/
1780void QTextEdit::dropEvent(QDropEvent *e)
1781{
1782 Q_D(QTextEdit);
1783 d->inDrag = false;
1784 d->autoScrollTimer.stop();
1785 d->sendControlEvent(e);
1786}
1787
1788#endif // QT_CONFIG(draganddrop)
1789
1790/*! \reimp
1791 */
1792void QTextEdit::inputMethodEvent(QInputMethodEvent *e)
1793{
1794 Q_D(QTextEdit);
1795#ifdef QT_KEYPAD_NAVIGATION
1796 if (d->control->textInteractionFlags() & Qt::TextEditable
1797 && QApplicationPrivate::keypadNavigationEnabled()
1798 && !hasEditFocus())
1799 setEditFocus(true);
1800#endif
1801 d->sendControlEvent(e);
1802 const bool emptyEvent = e->preeditString().isEmpty() && e->commitString().isEmpty()
1803 && e->attributes().isEmpty();
1804 if (emptyEvent)
1805 return;
1806 ensureCursorVisible();
1807}
1808
1809/*!\reimp
1810*/
1811void QTextEdit::scrollContentsBy(int dx, int dy)
1812{
1813 Q_D(QTextEdit);
1814 if (isRightToLeft())
1815 dx = -dx;
1816 d->viewport->scroll(dx, dy);
1817 QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
1818}
1819
1820/*!\reimp
1821*/
1822QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1823{
1824 return inputMethodQuery(property, QVariant());
1825}
1826
1827/*!\internal
1828 */
1829QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const
1830{
1831 Q_D(const QTextEdit);
1832 switch (query) {
1833 case Qt::ImEnabled:
1834 return isEnabled() && !isReadOnly();
1835 case Qt::ImHints:
1836 case Qt::ImInputItemClipRectangle:
1837 return QWidget::inputMethodQuery(query);
1838 case Qt::ImReadOnly:
1839 return isReadOnly();
1840 default:
1841 break;
1842 }
1843
1844 const QPointF offset(-d->horizontalOffset(), -d->verticalOffset());
1845 switch (argument.userType()) {
1846 case QMetaType::QRectF:
1847 argument = argument.toRectF().translated(-offset);
1848 break;
1849 case QMetaType::QPointF:
1850 argument = argument.toPointF() - offset;
1851 break;
1852 case QMetaType::QRect:
1853 argument = argument.toRect().translated(-offset.toPoint());
1854 break;
1855 case QMetaType::QPoint:
1856 argument = argument.toPoint() - offset;
1857 break;
1858 default:
1859 break;
1860 }
1861
1862 const QVariant v = d->control->inputMethodQuery(query, argument);
1863 switch (v.userType()) {
1864 case QMetaType::QRectF:
1865 return v.toRectF().translated(offset);
1866 case QMetaType::QPointF:
1867 return v.toPointF() + offset;
1868 case QMetaType::QRect:
1869 return v.toRect().translated(offset.toPoint());
1870 case QMetaType::QPoint:
1871 return v.toPoint() + offset.toPoint();
1872 default:
1873 break;
1874 }
1875 return v;
1876}
1877
1878/*! \reimp
1879*/
1880void QTextEdit::focusInEvent(QFocusEvent *e)
1881{
1882 Q_D(QTextEdit);
1883 if (e->reason() == Qt::MouseFocusReason) {
1884 d->clickCausedFocus = 1;
1885 }
1886 QAbstractScrollArea::focusInEvent(e);
1887 d->sendControlEvent(e);
1888}
1889
1890/*! \reimp
1891*/
1892void QTextEdit::focusOutEvent(QFocusEvent *e)
1893{
1894 Q_D(QTextEdit);
1895 QAbstractScrollArea::focusOutEvent(e);
1896 d->sendControlEvent(e);
1897}
1898
1899/*! \reimp
1900*/
1901void QTextEdit::showEvent(QShowEvent *)
1902{
1903 Q_D(QTextEdit);
1904 if (!d->anchorToScrollToWhenVisible.isEmpty()) {
1905 scrollToAnchor(d->anchorToScrollToWhenVisible);
1906 d->anchorToScrollToWhenVisible.clear();
1907 d->showCursorOnInitialShow = false;
1908 } else if (d->showCursorOnInitialShow) {
1909 d->showCursorOnInitialShow = false;
1910 ensureCursorVisible();
1911 }
1912}
1913
1914/*! \reimp
1915*/
1916void QTextEdit::changeEvent(QEvent *e)
1917{
1918 Q_D(QTextEdit);
1919 QAbstractScrollArea::changeEvent(e);
1920 if (e->type() == QEvent::ApplicationFontChange
1921 || e->type() == QEvent::FontChange) {
1922 d->control->document()->setDefaultFont(font());
1923 } else if (e->type() == QEvent::ActivationChange) {
1924 if (!isActiveWindow())
1925 d->autoScrollTimer.stop();
1926 } else if (e->type() == QEvent::EnabledChange) {
1927 e->setAccepted(isEnabled());
1928 d->control->setPalette(palette());
1929 d->sendControlEvent(e);
1930 } else if (e->type() == QEvent::PaletteChange) {
1931 d->control->setPalette(palette());
1932 } else if (e->type() == QEvent::LayoutDirectionChange) {
1933 d->sendControlEvent(e);
1934 }
1935}
1936
1937/*! \reimp
1938*/
1939#if QT_CONFIG(wheelevent)
1940void QTextEdit::wheelEvent(QWheelEvent *e)
1941{
1942 Q_D(QTextEdit);
1943 if (!(d->control->textInteractionFlags() & Qt::TextEditable)) {
1944 if (e->modifiers() & Qt::ControlModifier) {
1945 float delta = e->angleDelta().y() / 120.f;
1946 zoomInF(delta);
1947 return;
1948 }
1949 }
1950 QAbstractScrollArea::wheelEvent(e);
1951 updateMicroFocus();
1952}
1953#endif
1954
1955#ifndef QT_NO_CONTEXTMENU
1956/*! This function creates the standard context menu which is shown
1957 when the user clicks on the text edit with the right mouse
1958 button. It is called from the default contextMenuEvent() handler.
1959 The popup menu's ownership is transferred to the caller.
1960
1961 We recommend that you use the createStandardContextMenu(QPoint) version instead
1962 which will enable the actions that are sensitive to where the user clicked.
1963*/
1964
1965QMenu *QTextEdit::createStandardContextMenu()
1966{
1967 Q_D(QTextEdit);
1968 return d->control->createStandardContextMenu(QPointF(), this);
1969}
1970
1971/*!
1972 \since 4.4
1973 This function creates the standard context menu which is shown
1974 when the user clicks on the text edit with the right mouse
1975 button. It is called from the default contextMenuEvent() handler
1976 and it takes the \a position in document coordinates where the mouse click was.
1977 This can enable actions that are sensitive to the position where the user clicked.
1978 The popup menu's ownership is transferred to the caller.
1979*/
1980
1981QMenu *QTextEdit::createStandardContextMenu(const QPoint &position)
1982{
1983 Q_D(QTextEdit);
1984 return d->control->createStandardContextMenu(position, this);
1985}
1986#endif // QT_NO_CONTEXTMENU
1987
1988/*!
1989 returns a QTextCursor at position \a pos (in viewport coordinates).
1990*/
1991QTextCursor QTextEdit::cursorForPosition(const QPoint &pos) const
1992{
1993 Q_D(const QTextEdit);
1994 return d->control->cursorForPosition(d->mapToContents(pos));
1995}
1996
1997/*!
1998 returns a rectangle (in viewport coordinates) that includes the
1999 \a cursor.
2000 */
2001QRect QTextEdit::cursorRect(const QTextCursor &cursor) const
2002{
2003 Q_D(const QTextEdit);
2004 if (cursor.isNull())
2005 return QRect();
2006
2007 QRect r = d->control->cursorRect(cursor).toRect();
2008 r.translate(-d->horizontalOffset(),-d->verticalOffset());
2009 return r;
2010}
2011
2012/*!
2013 returns a rectangle (in viewport coordinates) that includes the
2014 cursor of the text edit.
2015 */
2016QRect QTextEdit::cursorRect() const
2017{
2018 Q_D(const QTextEdit);
2019 QRect r = d->control->cursorRect().toRect();
2020 r.translate(-d->horizontalOffset(),-d->verticalOffset());
2021 return r;
2022}
2023
2024
2025/*!
2026 Returns the reference of the anchor at position \a pos, or an
2027 empty string if no anchor exists at that point.
2028*/
2029QString QTextEdit::anchorAt(const QPoint& pos) const
2030{
2031 Q_D(const QTextEdit);
2032 return d->control->anchorAt(d->mapToContents(pos));
2033}
2034
2035/*!
2036 \property QTextEdit::overwriteMode
2037 \since 4.1
2038 \brief whether text entered by the user will overwrite existing text
2039
2040 As with many text editors, the text editor widget can be configured
2041 to insert or overwrite existing text with new text entered by the user.
2042
2043 If this property is \c true, existing text is overwritten, character-for-character
2044 by new text; otherwise, text is inserted at the cursor position, displacing
2045 existing text.
2046
2047 By default, this property is \c false (new text does not overwrite existing text).
2048*/
2049
2050bool QTextEdit::overwriteMode() const
2051{
2052 Q_D(const QTextEdit);
2053 return d->control->overwriteMode();
2054}
2055
2056void QTextEdit::setOverwriteMode(bool overwrite)
2057{
2058 Q_D(QTextEdit);
2059 d->control->setOverwriteMode(overwrite);
2060}
2061
2062/*!
2063 \property QTextEdit::tabStopDistance
2064 \brief the tab stop distance in pixels
2065 \since 5.10
2066
2067 By default, this property contains a value of 80 pixels.
2068
2069 Do not set a value less than the \l {QFontMetrics::}{horizontalAdvance()}
2070 of the QChar::VisualTabCharacter character, otherwise the tab-character
2071 will be drawn incompletely.
2072
2073 \sa QTextOption::ShowTabsAndSpaces, QTextDocument::defaultTextOption
2074*/
2075
2076qreal QTextEdit::tabStopDistance() const
2077{
2078 Q_D(const QTextEdit);
2079 return d->control->document()->defaultTextOption().tabStopDistance();
2080}
2081
2082void QTextEdit::setTabStopDistance(qreal distance)
2083{
2084 Q_D(QTextEdit);
2085 QTextOption opt = d->control->document()->defaultTextOption();
2086 if (opt.tabStopDistance() == distance || distance < 0)
2087 return;
2088 opt.setTabStopDistance(distance);
2089 d->control->document()->setDefaultTextOption(opt);
2090}
2091
2092/*!
2093 \since 4.2
2094 \property QTextEdit::cursorWidth
2095
2096 This property specifies the width of the cursor in pixels. The default value is 1.
2097*/
2098int QTextEdit::cursorWidth() const
2099{
2100 Q_D(const QTextEdit);
2101 return d->control->cursorWidth();
2102}
2103
2104void QTextEdit::setCursorWidth(int width)
2105{
2106 Q_D(QTextEdit);
2107 d->control->setCursorWidth(width);
2108}
2109
2110/*!
2111 \property QTextEdit::acceptRichText
2112 \brief whether the text edit accepts rich text insertions by the user
2113 \since 4.1
2114
2115 When this property is set to false text edit will accept only
2116 plain text input from the user. For example through clipboard or drag and drop.
2117
2118 This property's default is true.
2119*/
2120
2121bool QTextEdit::acceptRichText() const
2122{
2123 Q_D(const QTextEdit);
2124 return d->control->acceptRichText();
2125}
2126
2127void QTextEdit::setAcceptRichText(bool accept)
2128{
2129 Q_D(QTextEdit);
2130 d->control->setAcceptRichText(accept);
2131}
2132
2133/*!
2134 \class QTextEdit::ExtraSelection
2135 \since 4.2
2136 \inmodule QtWidgets
2137
2138 \brief The QTextEdit::ExtraSelection structure provides a way of specifying a
2139 character format for a given selection in a document.
2140*/
2141
2142/*!
2143 \variable QTextEdit::ExtraSelection::cursor
2144 A cursor that contains a selection in a QTextDocument
2145*/
2146
2147/*!
2148 \variable QTextEdit::ExtraSelection::format
2149 A format that is used to specify a foreground or background brush/color
2150 for the selection.
2151*/
2152
2153/*!
2154 \since 4.2
2155 This function allows temporarily marking certain regions in the document
2156 with a given color, specified as \a selections. This can be useful for
2157 example in a programming editor to mark a whole line of text with a given
2158 background color to indicate the existence of a breakpoint.
2159
2160 \sa QTextEdit::ExtraSelection, extraSelections()
2161*/
2162void QTextEdit::setExtraSelections(const QList<ExtraSelection> &selections)
2163{
2164 Q_D(QTextEdit);
2165 d->control->setExtraSelections(selections);
2166}
2167
2168/*!
2169 \since 4.2
2170 Returns previously set extra selections.
2171
2172 \sa setExtraSelections()
2173*/
2174QList<QTextEdit::ExtraSelection> QTextEdit::extraSelections() const
2175{
2176 Q_D(const QTextEdit);
2177 return d->control->extraSelections();
2178}
2179
2180/*!
2181 This function returns a new MIME data object to represent the contents
2182 of the text edit's current selection. It is called when the selection needs
2183 to be encapsulated into a new QMimeData object; for example, when a drag
2184 and drop operation is started, or when data is copied to the clipboard.
2185
2186 If you reimplement this function, note that the ownership of the returned
2187 QMimeData object is passed to the caller. The selection can be retrieved
2188 by using the textCursor() function.
2189*/
2190QMimeData *QTextEdit::createMimeDataFromSelection() const
2191{
2192 Q_D(const QTextEdit);
2193 return d->control->QWidgetTextControl::createMimeDataFromSelection();
2194}
2195
2196/*!
2197 This function returns \c true if the contents of the MIME data object, specified
2198 by \a source, can be decoded and inserted into the document. It is called
2199 for example when during a drag operation the mouse enters this widget and it
2200 is necessary to determine whether it is possible to accept the drag and drop
2201 operation.
2202
2203 Reimplement this function to enable drag and drop support for additional MIME types.
2204 */
2205bool QTextEdit::canInsertFromMimeData(const QMimeData *source) const
2206{
2207 Q_D(const QTextEdit);
2208 return d->control->QWidgetTextControl::canInsertFromMimeData(source);
2209}
2210
2211/*!
2212 This function inserts the contents of the MIME data object, specified
2213 by \a source, into the text edit at the current cursor position. It is
2214 called whenever text is inserted as the result of a clipboard paste
2215 operation, or when the text edit accepts data from a drag and drop
2216 operation.
2217
2218 Reimplement this function to enable drag and drop support for additional MIME types.
2219 */
2220void QTextEdit::insertFromMimeData(const QMimeData *source)
2221{
2222 Q_D(QTextEdit);
2223 d->control->QWidgetTextControl::insertFromMimeData(source);
2224}
2225
2226/*!
2227 \property QTextEdit::readOnly
2228 \brief whether the text edit is read-only
2229
2230 In a read-only text edit the user can only navigate through the
2231 text and select text; modifying the text is not possible.
2232
2233 This property's default is false.
2234*/
2235
2236bool QTextEdit::isReadOnly() const
2237{
2238 Q_D(const QTextEdit);
2239 return !d->control || !(d->control->textInteractionFlags() & Qt::TextEditable);
2240}
2241
2242void QTextEdit::setReadOnly(bool ro)
2243{
2244 Q_D(QTextEdit);
2245 Qt::TextInteractionFlags flags = Qt::NoTextInteraction;
2246 if (ro) {
2247 flags = Qt::TextSelectableByMouse;
2248#if QT_CONFIG(textbrowser)
2249 if (qobject_cast<QTextBrowser *>(this))
2250 flags |= Qt::TextBrowserInteraction;
2251#endif
2252 } else {
2253 flags = Qt::TextEditorInteraction;
2254 }
2255 d->control->setTextInteractionFlags(flags);
2256 setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this));
2257 QEvent event(QEvent::ReadOnlyChange);
2258 QCoreApplication::sendEvent(this, &event);
2259}
2260
2261/*!
2262 \property QTextEdit::textInteractionFlags
2263 \since 4.2
2264
2265 Specifies how the widget should interact with user input.
2266
2267 The default value depends on whether the QTextEdit is read-only
2268 or editable, and whether it is a QTextBrowser or not.
2269*/
2270
2271void QTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
2272{
2273 Q_D(QTextEdit);
2274 d->control->setTextInteractionFlags(flags);
2275}
2276
2277Qt::TextInteractionFlags QTextEdit::textInteractionFlags() const
2278{
2279 Q_D(const QTextEdit);
2280 return d->control->textInteractionFlags();
2281}
2282
2283/*!
2284 Merges the properties specified in \a modifier into the current character
2285 format by calling QTextCursor::mergeCharFormat on the editor's cursor.
2286 If the editor has a selection then the properties of \a modifier are
2287 directly applied to the selection.
2288
2289 \sa QTextCursor::mergeCharFormat()
2290 */
2291void QTextEdit::mergeCurrentCharFormat(const QTextCharFormat &modifier)
2292{
2293 Q_D(QTextEdit);
2294 d->control->mergeCurrentCharFormat(modifier);
2295}
2296
2297/*!
2298 Sets the char format that is be used when inserting new text to \a
2299 format by calling QTextCursor::setCharFormat() on the editor's
2300 cursor. If the editor has a selection then the char format is
2301 directly applied to the selection.
2302 */
2303void QTextEdit::setCurrentCharFormat(const QTextCharFormat &format)
2304{
2305 Q_D(QTextEdit);
2306 d->control->setCurrentCharFormat(format);
2307}
2308
2309/*!
2310 Returns the char format that is used when inserting new text.
2311 */
2312QTextCharFormat QTextEdit::currentCharFormat() const
2313{
2314 Q_D(const QTextEdit);
2315 return d->control->currentCharFormat();
2316}
2317
2318/*!
2319 \property QTextEdit::autoFormatting
2320 \brief the enabled set of auto formatting features
2321
2322 The value can be any combination of the values in the
2323 AutoFormattingFlag enum. The default is AutoNone. Choose
2324 AutoAll to enable all automatic formatting.
2325
2326 Currently, the only automatic formatting feature provided is
2327 AutoBulletList; future versions of Qt may offer more.
2328*/
2329
2330QTextEdit::AutoFormatting QTextEdit::autoFormatting() const
2331{
2332 Q_D(const QTextEdit);
2333 return d->autoFormatting;
2334}
2335
2336void QTextEdit::setAutoFormatting(AutoFormatting features)
2337{
2338 Q_D(QTextEdit);
2339 d->autoFormatting = features;
2340}
2341
2342/*!
2343 Convenience slot that inserts \a text at the current
2344 cursor position.
2345
2346 It is equivalent to
2347
2348 \snippet code/src_gui_widgets_qtextedit.cpp 1
2349 */
2350void QTextEdit::insertPlainText(const QString &text)
2351{
2352 Q_D(QTextEdit);
2353 d->control->insertPlainText(text);
2354}
2355
2356/*!
2357 Convenience slot that inserts \a text which is assumed to be of
2358 html formatting at the current cursor position.
2359
2360 It is equivalent to:
2361
2362 \snippet code/src_gui_widgets_qtextedit.cpp 2
2363
2364 \note When using this function with a style sheet, the style sheet will
2365 only apply to the current block in the document. In order to apply a style
2366 sheet throughout a document, use QTextDocument::setDefaultStyleSheet()
2367 instead.
2368 */
2369#ifndef QT_NO_TEXTHTMLPARSER
2370void QTextEdit::insertHtml(const QString &text)
2371{
2372 Q_D(QTextEdit);
2373 d->control->insertHtml(text);
2374}
2375#endif // QT_NO_TEXTHTMLPARSER
2376
2377/*!
2378 Scrolls the text edit so that the anchor with the given \a name is
2379 visible; does nothing if the \a name is empty, or is already
2380 visible, or isn't found.
2381*/
2382void QTextEdit::scrollToAnchor(const QString &name)
2383{
2384 Q_D(QTextEdit);
2385 if (name.isEmpty())
2386 return;
2387
2388 if (!isVisible()) {
2389 d->anchorToScrollToWhenVisible = name;
2390 return;
2391 }
2392
2393 QPointF p = d->control->anchorPosition(name);
2394 const int newPosition = qRound(p.y());
2395 if ( d->vbar->maximum() < newPosition )
2396 d->adjustScrollbars();
2397 d->vbar->setValue(newPosition);
2398}
2399
2400/*!
2401 Zooms in on the text by making the base font size \a range
2402 points larger and recalculating all font sizes to be the new size.
2403 This does not change the size of any images.
2404
2405 \sa zoomOut()
2406*/
2407void QTextEdit::zoomIn(int range)
2408{
2409 zoomInF(range);
2410}
2411
2412/*!
2413 Zooms out on the text by making the base font size \a range points
2414 smaller and recalculating all font sizes to be the new size. This
2415 does not change the size of any images.
2416
2417 \sa zoomIn()
2418*/
2419void QTextEdit::zoomOut(int range)
2420{
2421 zoomInF(-range);
2422}
2423
2424/*!
2425 \internal
2426*/
2427void QTextEdit::zoomInF(float range)
2428{
2429 if (range == 0.f)
2430 return;
2431 QFont f = font();
2432 const float newSize = f.pointSizeF() + range;
2433 if (newSize <= 0)
2434 return;
2435 f.setPointSizeF(newSize);
2436 setFont(f);
2437}
2438
2439/*!
2440 \since 4.2
2441 Moves the cursor by performing the given \a operation.
2442
2443 If \a mode is QTextCursor::KeepAnchor, the cursor selects the text it moves over.
2444 This is the same effect that the user achieves when they hold down the Shift key
2445 and move the cursor with the cursor keys.
2446
2447 \sa QTextCursor::movePosition()
2448*/
2449void QTextEdit::moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode)
2450{
2451 Q_D(QTextEdit);
2452 d->control->moveCursor(operation, mode);
2453}
2454
2455/*!
2456 \since 4.2
2457 Returns whether text can be pasted from the clipboard into the textedit.
2458*/
2459bool QTextEdit::canPaste() const
2460{
2461 Q_D(const QTextEdit);
2462 return d->control->canPaste();
2463}
2464
2465/*!
2466 \since 4.3
2467 Convenience function to print the text edit's document to the given \a printer. This
2468 is equivalent to calling the print method on the document directly except that this
2469 function also supports QPrinter::Selection as print range.
2470
2471 \sa QTextDocument::print()
2472*/
2473#ifndef QT_NO_PRINTER
2474void QTextEdit::print(QPagedPaintDevice *printer) const
2475{
2476 Q_D(const QTextEdit);
2477 d->control->print(printer);
2478}
2479#endif
2480
2481/*! \property QTextEdit::tabChangesFocus
2482 \brief whether \uicontrol Tab changes focus or is accepted as input
2483
2484 In some occasions text edits should not allow the user to input
2485 tabulators or change indentation using the \uicontrol Tab key, as this breaks
2486 the focus chain. The default is false.
2487
2488*/
2489
2490bool QTextEdit::tabChangesFocus() const
2491{
2492 Q_D(const QTextEdit);
2493 return d->tabChangesFocus;
2494}
2495
2496void QTextEdit::setTabChangesFocus(bool b)
2497{
2498 Q_D(QTextEdit);
2499 d->tabChangesFocus = b;
2500}
2501
2502/*!
2503 \property QTextEdit::documentTitle
2504 \brief the title of the document parsed from the text.
2505
2506 By default, for a newly-created, empty document, this property contains
2507 an empty string.
2508*/
2509
2510/*!
2511 \property QTextEdit::lineWrapMode
2512 \brief the line wrap mode
2513
2514 The default mode is WidgetWidth which causes words to be
2515 wrapped at the right edge of the text edit. Wrapping occurs at
2516 whitespace, keeping whole words intact. If you want wrapping to
2517 occur within words use setWordWrapMode(). If you set a wrap mode of
2518 FixedPixelWidth or FixedColumnWidth you should also call
2519 setLineWrapColumnOrWidth() with the width you want.
2520
2521 \sa lineWrapColumnOrWidth
2522*/
2523
2524QTextEdit::LineWrapMode QTextEdit::lineWrapMode() const
2525{
2526 Q_D(const QTextEdit);
2527 return d->lineWrap;
2528}
2529
2530void QTextEdit::setLineWrapMode(LineWrapMode wrap)
2531{
2532 Q_D(QTextEdit);
2533 if (d->lineWrap == wrap)
2534 return;
2535 d->lineWrap = wrap;
2536 d->updateDefaultTextOption();
2537 d->relayoutDocument();
2538}
2539
2540/*!
2541 \property QTextEdit::lineWrapColumnOrWidth
2542 \brief the position (in pixels or columns depending on the wrap mode) where text will be wrapped
2543
2544 If the wrap mode is FixedPixelWidth, the value is the number of
2545 pixels from the left edge of the text edit at which text should be
2546 wrapped. If the wrap mode is FixedColumnWidth, the value is the
2547 column number (in character columns) from the left edge of the
2548 text edit at which text should be wrapped.
2549
2550 By default, this property contains a value of 0.
2551
2552 \sa lineWrapMode
2553*/
2554
2555int QTextEdit::lineWrapColumnOrWidth() const
2556{
2557 Q_D(const QTextEdit);
2558 return d->lineWrapColumnOrWidth;
2559}
2560
2561void QTextEdit::setLineWrapColumnOrWidth(int w)
2562{
2563 Q_D(QTextEdit);
2564 d->lineWrapColumnOrWidth = w;
2565 d->relayoutDocument();
2566}
2567
2568/*!
2569 \property QTextEdit::wordWrapMode
2570 \brief the mode QTextEdit will use when wrapping text by words
2571
2572 By default, this property is set to QTextOption::WrapAtWordBoundaryOrAnywhere.
2573
2574 \sa QTextOption::WrapMode
2575*/
2576
2577QTextOption::WrapMode QTextEdit::wordWrapMode() const
2578{
2579 Q_D(const QTextEdit);
2580 return d->wordWrap;
2581}
2582
2583void QTextEdit::setWordWrapMode(QTextOption::WrapMode mode)
2584{
2585 Q_D(QTextEdit);
2586 if (mode == d->wordWrap)
2587 return;
2588 d->wordWrap = mode;
2589 d->updateDefaultTextOption();
2590}
2591
2592/*!
2593 Finds the next occurrence of the string, \a exp, using the given
2594 \a options. Returns \c true if \a exp was found and changes the
2595 cursor to select the match; otherwise returns \c false.
2596*/
2597bool QTextEdit::find(const QString &exp, QTextDocument::FindFlags options)
2598{
2599 Q_D(QTextEdit);
2600 return d->control->find(exp, options);
2601}
2602
2603/*!
2604 \fn bool QTextEdit::find(const QRegularExpression &exp, QTextDocument::FindFlags options)
2605
2606 \since 5.13
2607 \overload
2608
2609 Finds the next occurrence, matching the regular expression, \a exp, using the given
2610 \a options.
2611
2612 Returns \c true if a match was found and changes the cursor to select the match;
2613 otherwise returns \c false.
2614
2615 \warning For historical reasons, the case sensitivity option set on
2616 \a exp is ignored. Instead, the \a options are used to determine
2617 if the search is case sensitive or not.
2618*/
2619#if QT_CONFIG(regularexpression)
2620bool QTextEdit::find(const QRegularExpression &exp, QTextDocument::FindFlags options)
2621{
2622 Q_D(QTextEdit);
2623 return d->control->find(exp, options);
2624}
2625#endif
2626
2627/*!
2628 \fn void QTextEdit::copyAvailable(bool yes)
2629
2630 This signal is emitted when text is selected or de-selected in the
2631 text edit.
2632
2633 When text is selected this signal will be emitted with \a yes set
2634 to true. If no text has been selected or if the selected text is
2635 de-selected this signal is emitted with \a yes set to false.
2636
2637 If \a yes is true then copy() can be used to copy the selection to
2638 the clipboard. If \a yes is false then copy() does nothing.
2639
2640 \sa selectionChanged()
2641*/
2642
2643/*!
2644 \fn void QTextEdit::currentCharFormatChanged(const QTextCharFormat &f)
2645
2646 This signal is emitted if the current character format has changed, for
2647 example caused by a change of the cursor position.
2648
2649 The new format is \a f.
2650
2651 \sa setCurrentCharFormat()
2652*/
2653
2654/*!
2655 \fn void QTextEdit::selectionChanged()
2656
2657 This signal is emitted whenever the selection changes.
2658
2659 \sa copyAvailable()
2660*/
2661
2662/*!
2663 \fn void QTextEdit::cursorPositionChanged()
2664
2665 This signal is emitted whenever the position of the
2666 cursor changed.
2667*/
2668
2669/*!
2670 \since 4.2
2671
2672 Sets the text edit's \a text. The text can be plain text or HTML
2673 and the text edit will try to guess the right format.
2674
2675 Use setHtml() or setPlainText() directly to avoid text edit's guessing.
2676
2677 \sa toPlainText(), toHtml()
2678*/
2679void QTextEdit::setText(const QString &text)
2680{
2681 Qt::TextFormat format = Qt::mightBeRichText(text) ? Qt::RichText : Qt::PlainText;
2682#ifndef QT_NO_TEXTHTMLPARSER
2683 if (format == Qt::RichText)
2684 setHtml(text);
2685 else
2686#else
2687 Q_UNUSED(format);
2688#endif
2689 setPlainText(text);
2690}
2691
2692
2693/*!
2694 Appends a new paragraph with \a text to the end of the text edit.
2695
2696 \note The new paragraph appended will have the same character format and
2697 block format as the current paragraph, determined by the position of the cursor.
2698
2699 \sa currentCharFormat(), QTextCursor::blockFormat()
2700*/
2701
2702void QTextEdit::append(const QString &text)
2703{
2704 Q_D(QTextEdit);
2705 const bool atBottom = isReadOnly() ? d->verticalOffset() >= d->vbar->maximum() :
2706 d->control->textCursor().atEnd();
2707 d->control->append(text);
2708 if (atBottom)
2709 d->vbar->setValue(d->vbar->maximum());
2710}
2711
2712/*!
2713 Ensures that the cursor is visible by scrolling the text edit if
2714 necessary.
2715*/
2716void QTextEdit::ensureCursorVisible()
2717{
2718 Q_D(QTextEdit);
2719 d->control->ensureCursorVisible();
2720}
2721
2722/*!
2723 \fn void QTextEdit::textChanged()
2724
2725 This signal is emitted whenever the document's content changes; for
2726 example, when text is inserted or deleted, or when formatting is applied.
2727*/
2728
2729/*!
2730 \fn void QTextEdit::undoAvailable(bool available)
2731
2732 This signal is emitted whenever undo operations become available
2733 (\a available is true) or unavailable (\a available is false).
2734*/
2735
2736/*!
2737 \fn void QTextEdit::redoAvailable(bool available)
2738
2739 This signal is emitted whenever redo operations become available
2740 (\a available is true) or unavailable (\a available is false).
2741*/
2742
2743QT_END_NAMESPACE
2744
2745#include "moc_qtextedit.cpp"
friend class QPainter
QRect viewport() const
Returns the viewport rectangle.
virtual void insertFromMimeData(const QMimeData *source) override
Definition qtextedit.cpp:70
virtual QMimeData * createMimeDataFromSelection() const override
Definition qtextedit.cpp:58
QVariant loadResource(int type, const QUrl &name) override
Definition qtextedit.cpp:77
virtual bool canInsertFromMimeData(const QMimeData *source) const override
Definition qtextedit.cpp:64
QTextEditControl(QObject *parent)
Definition qtextedit.cpp:56
void pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode)
int horizontalOffset() const
Definition qtextedit_p.h:64
int verticalOffset() const
Definition qtextedit_p.h:66
void createAutoBulletList()
void cursorPositionChanged()
void adjustScrollbars()
void updateDefaultTextOption()
The QTextEdit class provides a widget that is used to edit and display both plain and rich text.
Definition qtextedit.h:27
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE bool shouldEnableInputMethod(QTextEdit *textedit)
Definition qtextedit.cpp:44