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