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