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 (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 default:
1113 break;
1114 }
1115 return QAbstractScrollArea::event(e);
1116}
1117
1118/*! \internal
1119*/
1120
1121void QTextEdit::timerEvent(QTimerEvent *e)
1122{
1123 Q_D(QTextEdit);
1124 if (e->timerId() == d->autoScrollTimer.timerId()) {
1125 QRect visible = d->viewport->rect();
1126 QPoint pos;
1127 if (d->inDrag) {
1128 pos = d->autoScrollDragPos;
1129 visible.adjust(qMin(visible.width()/3,20), qMin(visible.height()/3,20),
1130 -qMin(visible.width()/3,20), -qMin(visible.height()/3,20));
1131 } else {
1132 const QPoint globalPos = QCursor::pos();
1133 pos = d->viewport->mapFromGlobal(globalPos);
1134 QMouseEvent ev(QEvent::MouseMove, pos, mapTo(topLevelWidget(), pos), globalPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
1135 mouseMoveEvent(&ev);
1136 }
1137 int deltaY = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();
1138 int deltaX = qMax(pos.x() - visible.left(), visible.right() - pos.x()) - visible.width();
1139 int delta = qMax(deltaX, deltaY);
1140 if (delta >= 0) {
1141 if (delta < 7)
1142 delta = 7;
1143 int timeout = 4900 / (delta * delta);
1144 d->autoScrollTimer.start(timeout, this);
1145
1146 if (deltaY > 0)
1147 d->vbar->triggerAction(pos.y() < visible.center().y() ?
1148 QAbstractSlider::SliderSingleStepSub
1149 : QAbstractSlider::SliderSingleStepAdd);
1150 if (deltaX > 0)
1151 d->hbar->triggerAction(pos.x() < visible.center().x() ?
1152 QAbstractSlider::SliderSingleStepSub
1153 : QAbstractSlider::SliderSingleStepAdd);
1154 }
1155 }
1156}
1157
1158/*!
1159 Changes the text of the text edit to the string \a text.
1160 Any previous text is removed.
1161
1162 Notes:
1163 \list
1164 \li \a text is interpreted as plain text.
1165 \li The undo/redo history is also cleared.
1166 \li currentCharFormat() is reset, unless textCursor()
1167 is already at the beginning of the document.
1168 \endlist
1169
1170 \sa toPlainText()
1171*/
1172
1173void QTextEdit::setPlainText(const QString &text)
1174{
1175 Q_D(QTextEdit);
1176 d->control->setPlainText(text);
1177 d->preferRichText = false;
1178}
1179
1180/*!
1181 QString QTextEdit::toPlainText() const
1182
1183 Returns the text of the text edit as plain text.
1184
1185 \sa QTextEdit::setPlainText()
1186 */
1187QString QTextEdit::toPlainText() const
1188{
1189 Q_D(const QTextEdit);
1190 return d->control->toPlainText();
1191}
1192
1193/*!
1194 \property QTextEdit::html
1195
1196 This property provides an HTML interface to the text of the text edit.
1197
1198 toHtml() returns the text of the text edit as html.
1199
1200 setHtml() changes the text of the text edit. Any previous text is
1201 removed and the undo/redo history is cleared. The input text is
1202 interpreted as rich text in html format. currentCharFormat() is also
1203 reset, unless textCursor() is already at the beginning of the document.
1204
1205 \note It is the responsibility of the caller to make sure that the
1206 text is correctly decoded when a QString containing HTML is created
1207 and passed to setHtml().
1208
1209 By default, for a newly-created, empty document, this property contains
1210 text to describe an HTML 4.0 document with no body text.
1211
1212 \sa {Supported HTML Subset}, plainText
1213*/
1214
1215#ifndef QT_NO_TEXTHTMLPARSER
1216void QTextEdit::setHtml(const QString &text)
1217{
1218 Q_D(QTextEdit);
1219 d->control->setHtml(text);
1220 d->preferRichText = true;
1221}
1222
1223QString QTextEdit::toHtml() const
1224{
1225 Q_D(const QTextEdit);
1226 return d->control->toHtml();
1227}
1228#endif
1229
1230#if QT_CONFIG(textmarkdownreader) && QT_CONFIG(textmarkdownwriter)
1231/*!
1232 \property QTextEdit::markdown
1233
1234 This property provides a Markdown interface to the text of the text edit.
1235
1236 \c toMarkdown() returns the text of the text edit as "pure" Markdown,
1237 without any embedded HTML formatting. Some features that QTextDocument
1238 supports (such as the use of specific colors and named fonts) cannot be
1239 expressed in "pure" Markdown, and they will be omitted.
1240
1241 \c setMarkdown() changes the text of the text edit. Any previous text is
1242 removed and the undo/redo history is cleared. The input text is
1243 interpreted as rich text in Markdown format.
1244
1245 Parsing of HTML included in the \a markdown string is handled in the same
1246 way as in \l setHtml; however, Markdown formatting inside HTML blocks is
1247 not supported.
1248
1249 Some features of the parser can be enabled or disabled via the \a features
1250 argument:
1251
1252 \value MarkdownNoHTML
1253 Any HTML tags in the Markdown text will be discarded
1254 \value MarkdownDialectCommonMark
1255 The parser supports only the features standardized by CommonMark
1256 \value MarkdownDialectGitHub
1257 The parser supports the GitHub dialect
1258
1259 The default is \c MarkdownDialectGitHub.
1260
1261 \sa plainText, html, QTextDocument::toMarkdown(), QTextDocument::setMarkdown()
1262 \since 5.14
1263*/
1264#endif
1265
1266#if QT_CONFIG(textmarkdownreader)
1267void QTextEdit::setMarkdown(const QString &markdown)
1268{
1269 Q_D(const QTextEdit);
1270 d->control->setMarkdown(markdown);
1271}
1272#endif
1273
1274#if QT_CONFIG(textmarkdownwriter)
1275QString QTextEdit::toMarkdown(QTextDocument::MarkdownFeatures features) const
1276{
1277 Q_D(const QTextEdit);
1278 return d->control->toMarkdown(features);
1279}
1280#endif
1281
1282/*! \reimp
1283*/
1284void QTextEdit::keyPressEvent(QKeyEvent *e)
1285{
1286 Q_D(QTextEdit);
1287
1288#ifndef QT_NO_SHORTCUT
1289
1290 Qt::TextInteractionFlags tif = d->control->textInteractionFlags();
1291
1292 if (tif & Qt::TextSelectableByKeyboard){
1293 if (e == QKeySequence::SelectPreviousPage) {
1294 e->accept();
1295 d->pageUpDown(QTextCursor::Up, QTextCursor::KeepAnchor);
1296 return;
1297 } else if (e ==QKeySequence::SelectNextPage) {
1298 e->accept();
1299 d->pageUpDown(QTextCursor::Down, QTextCursor::KeepAnchor);
1300 return;
1301 }
1302 }
1303 if (tif & (Qt::TextSelectableByKeyboard | Qt::TextEditable)) {
1304 if (e == QKeySequence::MoveToPreviousPage) {
1305 e->accept();
1306 d->pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor);
1307 return;
1308 } else if (e == QKeySequence::MoveToNextPage) {
1309 e->accept();
1310 d->pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor);
1311 return;
1312 }
1313 }
1314
1315 if (!(tif & Qt::TextEditable)) {
1316 switch (e->key()) {
1317 case Qt::Key_Space:
1318 e->accept();
1319 if (e->modifiers() & Qt::ShiftModifier)
1320 d->vbar->triggerAction(QAbstractSlider::SliderPageStepSub);
1321 else
1322 d->vbar->triggerAction(QAbstractSlider::SliderPageStepAdd);
1323 break;
1324 default:
1325 d->sendControlEvent(e);
1326 if (!e->isAccepted() && e->modifiers() == Qt::NoModifier) {
1327 if (e->key() == Qt::Key_Home) {
1328 d->vbar->triggerAction(QAbstractSlider::SliderToMinimum);
1329 e->accept();
1330 } else if (e->key() == Qt::Key_End) {
1331 d->vbar->triggerAction(QAbstractSlider::SliderToMaximum);
1332 e->accept();
1333 }
1334 }
1335 if (!e->isAccepted()) {
1336 QAbstractScrollArea::keyPressEvent(e);
1337 }
1338 }
1339 return;
1340 }
1341#endif // QT_NO_SHORTCUT
1342
1343 {
1344 QTextCursor cursor = d->control->textCursor();
1345 const QString text = e->text();
1346 if (cursor.atBlockStart()
1347 && (d->autoFormatting & AutoBulletList)
1348 && (text.size() == 1)
1349 && (text.at(0) == u'-' || text.at(0) == u'*')
1350 && (!cursor.currentList())) {
1351
1352 d->createAutoBulletList();
1353 e->accept();
1354 return;
1355 }
1356 }
1357
1358 d->sendControlEvent(e);
1359}
1360
1361/*! \reimp
1362*/
1363void QTextEdit::keyReleaseEvent(QKeyEvent *e)
1364{
1365 Q_D(QTextEdit);
1366 if (!isReadOnly())
1367 d->handleSoftwareInputPanel();
1368 e->ignore();
1369}
1370
1371/*!
1372 Loads the resource specified by the given \a type and \a name.
1373
1374 This function is an extension of QTextDocument::loadResource().
1375
1376 \sa QTextDocument::loadResource()
1377*/
1378QVariant QTextEdit::loadResource(int type, const QUrl &name)
1379{
1380 Q_UNUSED(type);
1381 Q_UNUSED(name);
1382 return QVariant();
1383}
1384
1385/*! \reimp
1386*/
1387void QTextEdit::resizeEvent(QResizeEvent *e)
1388{
1389 Q_D(QTextEdit);
1390
1391 if (d->lineWrap == NoWrap) {
1392 QTextDocument *doc = d->control->document();
1393 QVariant alignmentProperty = doc->documentLayout()->property("contentHasAlignment");
1394
1395 if (!doc->pageSize().isNull()
1396 && alignmentProperty.userType() == QMetaType::Bool
1397 && !alignmentProperty.toBool()) {
1398
1399 d->adjustScrollbars();
1400 return;
1401 }
1402 }
1403
1404 if (d->lineWrap != FixedPixelWidth
1405 && e->oldSize().width() != e->size().width())
1406 d->relayoutDocument();
1407 else
1408 d->adjustScrollbars();
1409}
1410
1412{
1413 QTextDocument *doc = control->document();
1414 QAbstractTextDocumentLayout *layout = doc->documentLayout();
1415
1416 if (QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout)) {
1417 if (lineWrap == QTextEdit::FixedColumnWidth)
1418 tlayout->setFixedColumnWidth(lineWrapColumnOrWidth);
1419 else
1420 tlayout->setFixedColumnWidth(-1);
1421 }
1422
1423 QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout);
1424 QSize lastUsedSize;
1425 if (tlayout)
1426 lastUsedSize = tlayout->dynamicDocumentSize().toSize();
1427 else
1428 lastUsedSize = layout->documentSize().toSize();
1429
1430 // ignore calls to adjustScrollbars caused by an emission of the
1431 // usedSizeChanged() signal in the layout, as we're calling it
1432 // later on our own anyway (or deliberately not) .
1433 const bool oldIgnoreScrollbarAdjustment = ignoreAutomaticScrollbarAdjustment;
1434 ignoreAutomaticScrollbarAdjustment = true;
1435
1436 int width = viewport->width();
1437 if (lineWrap == QTextEdit::FixedPixelWidth)
1438 width = lineWrapColumnOrWidth;
1439 else if (lineWrap == QTextEdit::NoWrap) {
1440 QVariant alignmentProperty = doc->documentLayout()->property("contentHasAlignment");
1441 if (alignmentProperty.userType() == QMetaType::Bool && !alignmentProperty.toBool()) {
1442
1443 width = 0;
1444 }
1445 }
1446
1447 doc->setPageSize(QSize(width, -1));
1448 if (tlayout)
1449 tlayout->ensureLayouted(verticalOffset() + viewport->height());
1450
1451 ignoreAutomaticScrollbarAdjustment = oldIgnoreScrollbarAdjustment;
1452
1453 QSize usedSize;
1454 if (tlayout)
1455 usedSize = tlayout->dynamicDocumentSize().toSize();
1456 else
1457 usedSize = layout->documentSize().toSize();
1458
1459 // this is an obscure situation in the layout that can happen:
1460 // if a character at the end of a line is the tallest one and therefore
1461 // influencing the total height of the line and the line right below it
1462 // is always taller though, then it can happen that if due to line breaking
1463 // that tall character wraps into the lower line the document not only shrinks
1464 // horizontally (causing the character to wrap in the first place) but also
1465 // vertically, because the original line is now smaller and the one below kept
1466 // its size. So a layout with less width _can_ take up less vertical space, too.
1467 // If the wider case causes a vertical scroll bar to appear and the narrower one
1468 // (narrower because the vertical scroll bar takes up horizontal space)) to disappear
1469 // again then we have an endless loop, as adjustScrollbars sets new ranges on the
1470 // scroll bars, the QAbstractScrollArea will find out about it and try to show/hide
1471 // the scroll bars again. That's why we try to detect this case here and break out.
1472 //
1473 // (if you change this please also check the layoutingLoop() testcase in
1474 // QTextEdit's autotests)
1475 if (lastUsedSize.isValid()
1476 && !vbar->isHidden()
1477 && viewport->width() < lastUsedSize.width()
1478 && usedSize.height() < lastUsedSize.height()
1479 && usedSize.height() <= viewport->height())
1480 return;
1481
1483}
1484
1485void QTextEditPrivate::paint(QPainter *p, QPaintEvent *e)
1486{
1487 const int xOffset = horizontalOffset();
1488 const int yOffset = verticalOffset();
1489
1490 QRect r = e->rect();
1491 p->translate(-xOffset, -yOffset);
1492 r.translate(xOffset, yOffset);
1493
1494 QTextDocument *doc = control->document();
1495 QTextDocumentLayout *layout = qobject_cast<QTextDocumentLayout *>(doc->documentLayout());
1496
1497 // the layout might need to expand the root frame to
1498 // the viewport if NoWrap is set
1499 if (layout)
1500 layout->setViewport(viewport->rect());
1501
1502 control->drawContents(p, r, q_func());
1503
1504 if (layout)
1505 layout->setViewport(QRect());
1506
1507 if (!placeholderText.isEmpty() && doc->isEmpty() && !control->isPreediting()) {
1508 const QColor col = control->palette().placeholderText().color();
1509 p->setPen(col);
1510 const int margin = int(doc->documentMargin());
1511 QRectF boundingRect = layout ? layout->frameBoundingRect(doc->rootFrame()) : viewport->rect();
1512 p->drawText(boundingRect.adjusted(margin, margin, -margin, -margin),
1513 Qt::AlignTop | Qt::TextWordWrap,
1514 placeholderText);
1515 }
1516}
1517
1518/*! \fn void QTextEdit::paintEvent(QPaintEvent *event)
1519
1520This event handler can be reimplemented in a subclass to receive paint events passed in \a event.
1521It is usually unnecessary to reimplement this function in a subclass of QTextEdit.
1522
1523\note If you create a QPainter, it must operate on the \l{QAbstractScrollArea::}{viewport()}.
1524
1525\warning The underlying text document must not be modified from within a reimplementation
1526of this function.
1527*/
1528void QTextEdit::paintEvent(QPaintEvent *e)
1529{
1530 Q_D(QTextEdit);
1531 QPainter p(d->viewport);
1532 d->paint(&p, e);
1533}
1534
1536{
1537 QTextDocument *doc = control->document();
1538
1539 QTextOption opt = doc->defaultTextOption();
1540 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1541
1542 if (lineWrap == QTextEdit::NoWrap)
1543 opt.setWrapMode(QTextOption::NoWrap);
1544 else
1545 opt.setWrapMode(wordWrap);
1546
1547 if (opt.wrapMode() != oldWrapMode)
1548 doc->setDefaultTextOption(opt);
1549}
1550
1551/*! \reimp
1552*/
1553void QTextEdit::mousePressEvent(QMouseEvent *e)
1554{
1555 Q_D(QTextEdit);
1556 d->sendControlEvent(e);
1557}
1558
1559/*! \reimp
1560*/
1561void QTextEdit::mouseMoveEvent(QMouseEvent *e)
1562{
1563 Q_D(QTextEdit);
1564 d->inDrag = false; // paranoia
1565 const QPoint pos = e->position().toPoint();
1566 d->sendControlEvent(e);
1567 if (!(e->buttons() & Qt::LeftButton))
1568 return;
1569 if (e->source() == Qt::MouseEventNotSynthesized) {
1570 const QRect visible = d->viewport->rect();
1571 if (visible.contains(pos))
1572 d->autoScrollTimer.stop();
1573 else if (!d->autoScrollTimer.isActive())
1574 d->autoScrollTimer.start(100, this);
1575 }
1576}
1577
1578/*! \reimp
1579*/
1580void QTextEdit::mouseReleaseEvent(QMouseEvent *e)
1581{
1582 Q_D(QTextEdit);
1583 d->sendControlEvent(e);
1584 if (e->source() == Qt::MouseEventNotSynthesized && d->autoScrollTimer.isActive()) {
1585 d->autoScrollTimer.stop();
1586 ensureCursorVisible();
1587 }
1588 if (!isReadOnly() && rect().contains(e->position().toPoint()))
1589 d->handleSoftwareInputPanel(e->button(), d->clickCausedFocus);
1590 d->clickCausedFocus = 0;
1591}
1592
1593/*! \reimp
1594*/
1595void QTextEdit::mouseDoubleClickEvent(QMouseEvent *e)
1596{
1597 Q_D(QTextEdit);
1598 d->sendControlEvent(e);
1599}
1600
1601/*! \reimp
1602*/
1603bool QTextEdit::focusNextPrevChild(bool next)
1604{
1605 Q_D(const QTextEdit);
1606 if (!d->tabChangesFocus && d->control->textInteractionFlags() & Qt::TextEditable)
1607 return false;
1608 return QAbstractScrollArea::focusNextPrevChild(next);
1609}
1610
1611#ifndef QT_NO_CONTEXTMENU
1612/*!
1613 \fn void QTextEdit::contextMenuEvent(QContextMenuEvent *event)
1614
1615 Shows the standard context menu created with createStandardContextMenu().
1616
1617 If you do not want the text edit to have a context menu, you can set
1618 its \l contextMenuPolicy to Qt::NoContextMenu. If you want to
1619 customize the context menu, reimplement this function. If you want
1620 to extend the standard context menu, reimplement this function, call
1621 createStandardContextMenu() and extend the menu returned.
1622
1623 Information about the event is passed in the \a event object.
1624
1625 \snippet code/src_gui_widgets_qtextedit.cpp 0
1626*/
1627void QTextEdit::contextMenuEvent(QContextMenuEvent *e)
1628{
1629 Q_D(QTextEdit);
1630 d->sendControlEvent(e);
1631}
1632#endif // QT_NO_CONTEXTMENU
1633
1634#if QT_CONFIG(draganddrop)
1635/*! \reimp
1636*/
1637void QTextEdit::dragEnterEvent(QDragEnterEvent *e)
1638{
1639 Q_D(QTextEdit);
1640 d->inDrag = true;
1641 d->sendControlEvent(e);
1642}
1643
1644/*! \reimp
1645*/
1646void QTextEdit::dragLeaveEvent(QDragLeaveEvent *e)
1647{
1648 Q_D(QTextEdit);
1649 d->inDrag = false;
1650 d->autoScrollTimer.stop();
1651 d->sendControlEvent(e);
1652}
1653
1654/*! \reimp
1655*/
1656void QTextEdit::dragMoveEvent(QDragMoveEvent *e)
1657{
1658 Q_D(QTextEdit);
1659 d->autoScrollDragPos = e->position().toPoint();
1660 if (!d->autoScrollTimer.isActive())
1661 d->autoScrollTimer.start(100, this);
1662 d->sendControlEvent(e);
1663}
1664
1665/*! \reimp
1666*/
1667void QTextEdit::dropEvent(QDropEvent *e)
1668{
1669 Q_D(QTextEdit);
1670 d->inDrag = false;
1671 d->autoScrollTimer.stop();
1672 d->sendControlEvent(e);
1673}
1674
1675#endif // QT_CONFIG(draganddrop)
1676
1677/*! \reimp
1678 */
1679void QTextEdit::inputMethodEvent(QInputMethodEvent *e)
1680{
1681 Q_D(QTextEdit);
1682 d->sendControlEvent(e);
1683 const bool emptyEvent = e->preeditString().isEmpty() && e->commitString().isEmpty()
1684 && e->attributes().isEmpty();
1685 if (emptyEvent)
1686 return;
1687 ensureCursorVisible();
1688}
1689
1690/*!\reimp
1691*/
1692void QTextEdit::scrollContentsBy(int dx, int dy)
1693{
1694 Q_D(QTextEdit);
1695 if (isRightToLeft())
1696 dx = -dx;
1697 d->viewport->scroll(dx, dy);
1698 QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
1699}
1700
1701/*!\reimp
1702*/
1703QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1704{
1705 return inputMethodQuery(property, QVariant());
1706}
1707
1708/*!\internal
1709 */
1710QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const
1711{
1712 Q_D(const QTextEdit);
1713 switch (query) {
1714 case Qt::ImEnabled:
1715 return isEnabled() && !isReadOnly();
1716 case Qt::ImHints:
1717 case Qt::ImInputItemClipRectangle:
1718 return QWidget::inputMethodQuery(query);
1719 case Qt::ImReadOnly:
1720 return isReadOnly();
1721 default:
1722 break;
1723 }
1724
1725 const QPointF offset(-d->horizontalOffset(), -d->verticalOffset());
1726 switch (argument.userType()) {
1727 case QMetaType::QRectF:
1728 argument = argument.toRectF().translated(-offset);
1729 break;
1730 case QMetaType::QPointF:
1731 argument = argument.toPointF() - offset;
1732 break;
1733 case QMetaType::QRect:
1734 argument = argument.toRect().translated(-offset.toPoint());
1735 break;
1736 case QMetaType::QPoint:
1737 argument = argument.toPoint() - offset;
1738 break;
1739 default:
1740 break;
1741 }
1742
1743 const QVariant v = d->control->inputMethodQuery(query, argument);
1744 switch (v.userType()) {
1745 case QMetaType::QRectF:
1746 return v.toRectF().translated(offset);
1747 case QMetaType::QPointF:
1748 return v.toPointF() + offset;
1749 case QMetaType::QRect:
1750 return v.toRect().translated(offset.toPoint());
1751 case QMetaType::QPoint:
1752 return v.toPoint() + offset.toPoint();
1753 default:
1754 break;
1755 }
1756 return v;
1757}
1758
1759/*! \reimp
1760*/
1761void QTextEdit::focusInEvent(QFocusEvent *e)
1762{
1763 Q_D(QTextEdit);
1764 if (e->reason() == Qt::MouseFocusReason) {
1765 d->clickCausedFocus = 1;
1766 }
1767 QAbstractScrollArea::focusInEvent(e);
1768 d->sendControlEvent(e);
1769}
1770
1771/*! \reimp
1772*/
1773void QTextEdit::focusOutEvent(QFocusEvent *e)
1774{
1775 Q_D(QTextEdit);
1776 QAbstractScrollArea::focusOutEvent(e);
1777 d->sendControlEvent(e);
1778}
1779
1780/*! \reimp
1781*/
1782void QTextEdit::showEvent(QShowEvent *)
1783{
1784 Q_D(QTextEdit);
1785 if (!d->anchorToScrollToWhenVisible.isEmpty()) {
1786 scrollToAnchor(d->anchorToScrollToWhenVisible);
1787 d->anchorToScrollToWhenVisible.clear();
1788 d->showCursorOnInitialShow = false;
1789 } else if (d->showCursorOnInitialShow) {
1790 d->showCursorOnInitialShow = false;
1791 ensureCursorVisible();
1792 }
1793}
1794
1795/*! \reimp
1796*/
1797void QTextEdit::changeEvent(QEvent *e)
1798{
1799 Q_D(QTextEdit);
1800 QAbstractScrollArea::changeEvent(e);
1801 if (e->type() == QEvent::ApplicationFontChange
1802 || e->type() == QEvent::FontChange) {
1803 d->control->document()->setDefaultFont(font());
1804 } else if (e->type() == QEvent::ActivationChange) {
1805 if (!isActiveWindow())
1806 d->autoScrollTimer.stop();
1807 } else if (e->type() == QEvent::EnabledChange) {
1808 e->setAccepted(isEnabled());
1809 d->control->setPalette(palette());
1810 d->sendControlEvent(e);
1811 } else if (e->type() == QEvent::PaletteChange) {
1812 d->control->setPalette(palette());
1813 } else if (e->type() == QEvent::LayoutDirectionChange) {
1814 d->sendControlEvent(e);
1815 }
1816}
1817
1818/*! \reimp
1819*/
1820#if QT_CONFIG(wheelevent)
1821void QTextEdit::wheelEvent(QWheelEvent *e)
1822{
1823 Q_D(QTextEdit);
1824 if (!(d->control->textInteractionFlags() & Qt::TextEditable)) {
1825 if (e->modifiers() & Qt::ControlModifier) {
1826 float delta = e->angleDelta().y() / 120.f;
1827 zoomInF(delta);
1828 return;
1829 }
1830 }
1831 QAbstractScrollArea::wheelEvent(e);
1832 updateMicroFocus();
1833}
1834#endif
1835
1836#ifndef QT_NO_CONTEXTMENU
1837/*! This function creates the standard context menu which is shown
1838 when the user clicks on the text edit with the right mouse
1839 button. It is called from the default contextMenuEvent() handler.
1840 The popup menu's ownership is transferred to the caller.
1841
1842 We recommend that you use the createStandardContextMenu(QPoint) version instead
1843 which will enable the actions that are sensitive to where the user clicked.
1844*/
1845
1846QMenu *QTextEdit::createStandardContextMenu()
1847{
1848 Q_D(QTextEdit);
1849 return d->control->createStandardContextMenu(QPointF(), this);
1850}
1851
1852/*!
1853 \since 4.4
1854 This function creates the standard context menu which is shown
1855 when the user clicks on the text edit with the right mouse
1856 button. It is called from the default contextMenuEvent() handler
1857 and it takes the \a position in document coordinates where the mouse click was.
1858 This can enable actions that are sensitive to the position where the user clicked.
1859 The popup menu's ownership is transferred to the caller.
1860*/
1861
1862QMenu *QTextEdit::createStandardContextMenu(const QPoint &position)
1863{
1864 Q_D(QTextEdit);
1865 return d->control->createStandardContextMenu(position, this);
1866}
1867#endif // QT_NO_CONTEXTMENU
1868
1869/*!
1870 returns a QTextCursor at position \a pos (in viewport coordinates).
1871*/
1872QTextCursor QTextEdit::cursorForPosition(const QPoint &pos) const
1873{
1874 Q_D(const QTextEdit);
1875 return d->control->cursorForPosition(d->mapToContents(pos));
1876}
1877
1878/*!
1879 returns a rectangle (in viewport coordinates) that includes the
1880 \a cursor.
1881 */
1882QRect QTextEdit::cursorRect(const QTextCursor &cursor) const
1883{
1884 Q_D(const QTextEdit);
1885 if (cursor.isNull())
1886 return QRect();
1887
1888 QRect r = d->control->cursorRect(cursor).toRect();
1889 r.translate(-d->horizontalOffset(),-d->verticalOffset());
1890 return r;
1891}
1892
1893/*!
1894 returns a rectangle (in viewport coordinates) that includes the
1895 cursor of the text edit.
1896 */
1897QRect QTextEdit::cursorRect() const
1898{
1899 Q_D(const QTextEdit);
1900 QRect r = d->control->cursorRect().toRect();
1901 r.translate(-d->horizontalOffset(),-d->verticalOffset());
1902 return r;
1903}
1904
1905
1906/*!
1907 Returns the reference of the anchor at position \a pos, or an
1908 empty string if no anchor exists at that point.
1909*/
1910QString QTextEdit::anchorAt(const QPoint& pos) const
1911{
1912 Q_D(const QTextEdit);
1913 return d->control->anchorAt(d->mapToContents(pos));
1914}
1915
1916/*!
1917 \property QTextEdit::overwriteMode
1918 \since 4.1
1919 \brief whether text entered by the user will overwrite existing text
1920
1921 As with many text editors, the text editor widget can be configured
1922 to insert or overwrite existing text with new text entered by the user.
1923
1924 If this property is \c true, existing text is overwritten, character-for-character
1925 by new text; otherwise, text is inserted at the cursor position, displacing
1926 existing text.
1927
1928 By default, this property is \c false (new text does not overwrite existing text).
1929*/
1930
1931bool QTextEdit::overwriteMode() const
1932{
1933 Q_D(const QTextEdit);
1934 return d->control->overwriteMode();
1935}
1936
1937void QTextEdit::setOverwriteMode(bool overwrite)
1938{
1939 Q_D(QTextEdit);
1940 d->control->setOverwriteMode(overwrite);
1941}
1942
1943/*!
1944 \property QTextEdit::tabStopDistance
1945 \brief the tab stop distance in pixels
1946 \since 5.10
1947
1948 By default, this property contains a value of 80 pixels.
1949
1950 Do not set a value less than the \l {QFontMetrics::}{horizontalAdvance()}
1951 of the QChar::VisualTabCharacter character, otherwise the tab-character
1952 will be drawn incompletely.
1953
1954 \sa QTextOption::ShowTabsAndSpaces, QTextDocument::defaultTextOption
1955*/
1956
1957qreal QTextEdit::tabStopDistance() const
1958{
1959 Q_D(const QTextEdit);
1960 return d->control->document()->defaultTextOption().tabStopDistance();
1961}
1962
1963void QTextEdit::setTabStopDistance(qreal distance)
1964{
1965 Q_D(QTextEdit);
1966 QTextOption opt = d->control->document()->defaultTextOption();
1967 if (opt.tabStopDistance() == distance || distance < 0)
1968 return;
1969 opt.setTabStopDistance(distance);
1970 d->control->document()->setDefaultTextOption(opt);
1971}
1972
1973/*!
1974 \since 4.2
1975 \property QTextEdit::cursorWidth
1976
1977 This property specifies the width of the cursor in pixels. The default value is 1.
1978*/
1979int QTextEdit::cursorWidth() const
1980{
1981 Q_D(const QTextEdit);
1982 return d->control->cursorWidth();
1983}
1984
1985void QTextEdit::setCursorWidth(int width)
1986{
1987 Q_D(QTextEdit);
1988 d->control->setCursorWidth(width);
1989}
1990
1991/*!
1992 \property QTextEdit::acceptRichText
1993 \brief whether the text edit accepts rich text insertions by the user
1994 \since 4.1
1995
1996 When this property is set to false text edit will accept only
1997 plain text input from the user. For example through clipboard or drag and drop.
1998
1999 This property's default is true.
2000*/
2001
2002bool QTextEdit::acceptRichText() const
2003{
2004 Q_D(const QTextEdit);
2005 return d->control->acceptRichText();
2006}
2007
2008void QTextEdit::setAcceptRichText(bool accept)
2009{
2010 Q_D(QTextEdit);
2011 d->control->setAcceptRichText(accept);
2012}
2013
2014/*!
2015 \class QTextEdit::ExtraSelection
2016 \since 4.2
2017 \inmodule QtWidgets
2018
2019 \brief The QTextEdit::ExtraSelection structure provides a way of specifying a
2020 character format for a given selection in a document.
2021*/
2022
2023/*!
2024 \variable QTextEdit::ExtraSelection::cursor
2025 A cursor that contains a selection in a QTextDocument
2026*/
2027
2028/*!
2029 \variable QTextEdit::ExtraSelection::format
2030 A format that is used to specify a foreground or background brush/color
2031 for the selection.
2032*/
2033
2034/*!
2035 \since 4.2
2036 This function allows temporarily marking certain regions in the document
2037 with a given color, specified as \a selections. This can be useful for
2038 example in a programming editor to mark a whole line of text with a given
2039 background color to indicate the existence of a breakpoint.
2040
2041 \sa QTextEdit::ExtraSelection, extraSelections()
2042*/
2043void QTextEdit::setExtraSelections(const QList<ExtraSelection> &selections)
2044{
2045 Q_D(QTextEdit);
2046 d->control->setExtraSelections(selections);
2047}
2048
2049/*!
2050 \since 4.2
2051 Returns previously set extra selections.
2052
2053 \sa setExtraSelections()
2054*/
2055QList<QTextEdit::ExtraSelection> QTextEdit::extraSelections() const
2056{
2057 Q_D(const QTextEdit);
2058 return d->control->extraSelections();
2059}
2060
2061/*!
2062 This function returns a new MIME data object to represent the contents
2063 of the text edit's current selection. It is called when the selection needs
2064 to be encapsulated into a new QMimeData object; for example, when a drag
2065 and drop operation is started, or when data is copied to the clipboard.
2066
2067 If you reimplement this function, note that the ownership of the returned
2068 QMimeData object is passed to the caller. The selection can be retrieved
2069 by using the textCursor() function.
2070*/
2071QMimeData *QTextEdit::createMimeDataFromSelection() const
2072{
2073 Q_D(const QTextEdit);
2074 return d->control->QWidgetTextControl::createMimeDataFromSelection();
2075}
2076
2077/*!
2078 This function returns \c true if the contents of the MIME data object, specified
2079 by \a source, can be decoded and inserted into the document. It is called
2080 for example when during a drag operation the mouse enters this widget and it
2081 is necessary to determine whether it is possible to accept the drag and drop
2082 operation.
2083
2084 Reimplement this function to enable drag and drop support for additional MIME types.
2085 */
2086bool QTextEdit::canInsertFromMimeData(const QMimeData *source) const
2087{
2088 Q_D(const QTextEdit);
2089 return d->control->QWidgetTextControl::canInsertFromMimeData(source);
2090}
2091
2092/*!
2093 This function inserts the contents of the MIME data object, specified
2094 by \a source, into the text edit at the current cursor position. It is
2095 called whenever text is inserted as the result of a clipboard paste
2096 operation, or when the text edit accepts data from a drag and drop
2097 operation.
2098
2099 Reimplement this function to enable drag and drop support for additional MIME types.
2100 */
2101void QTextEdit::insertFromMimeData(const QMimeData *source)
2102{
2103 Q_D(QTextEdit);
2104 d->control->QWidgetTextControl::insertFromMimeData(source);
2105}
2106
2107/*!
2108 \property QTextEdit::readOnly
2109 \brief whether the text edit is read-only
2110
2111 In a read-only text edit the user can only navigate through the
2112 text and select text; modifying the text is not possible.
2113
2114 This property's default is false.
2115*/
2116
2117bool QTextEdit::isReadOnly() const
2118{
2119 Q_D(const QTextEdit);
2120 return !d->control || !(d->control->textInteractionFlags() & Qt::TextEditable);
2121}
2122
2123void QTextEdit::setReadOnly(bool ro)
2124{
2125 Q_D(QTextEdit);
2126 Qt::TextInteractionFlags flags = Qt::NoTextInteraction;
2127 if (ro) {
2128 flags = Qt::TextSelectableByMouse;
2129#if QT_CONFIG(textbrowser)
2130 if (qobject_cast<QTextBrowser *>(this))
2131 flags |= Qt::TextBrowserInteraction;
2132#endif
2133 } else {
2134 flags = Qt::TextEditorInteraction;
2135 }
2136 d->control->setTextInteractionFlags(flags);
2137 setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this));
2138 QEvent event(QEvent::ReadOnlyChange);
2139 QCoreApplication::sendEvent(this, &event);
2140}
2141
2142/*!
2143 \property QTextEdit::textInteractionFlags
2144 \since 4.2
2145
2146 Specifies how the widget should interact with user input.
2147
2148 The default value depends on whether the QTextEdit is read-only
2149 or editable, and whether it is a QTextBrowser or not.
2150*/
2151
2152void QTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
2153{
2154 Q_D(QTextEdit);
2155 d->control->setTextInteractionFlags(flags);
2156}
2157
2158Qt::TextInteractionFlags QTextEdit::textInteractionFlags() const
2159{
2160 Q_D(const QTextEdit);
2161 return d->control->textInteractionFlags();
2162}
2163
2164/*!
2165 Merges the properties specified in \a modifier into the current character
2166 format by calling QTextCursor::mergeCharFormat on the editor's cursor.
2167 If the editor has a selection then the properties of \a modifier are
2168 directly applied to the selection.
2169
2170 \sa QTextCursor::mergeCharFormat()
2171 */
2172void QTextEdit::mergeCurrentCharFormat(const QTextCharFormat &modifier)
2173{
2174 Q_D(QTextEdit);
2175 d->control->mergeCurrentCharFormat(modifier);
2176}
2177
2178/*!
2179 Sets the char format that is be used when inserting new text to \a
2180 format by calling QTextCursor::setCharFormat() on the editor's
2181 cursor. If the editor has a selection then the char format is
2182 directly applied to the selection.
2183 */
2184void QTextEdit::setCurrentCharFormat(const QTextCharFormat &format)
2185{
2186 Q_D(QTextEdit);
2187 d->control->setCurrentCharFormat(format);
2188}
2189
2190/*!
2191 Returns the char format that is used when inserting new text.
2192 */
2193QTextCharFormat QTextEdit::currentCharFormat() const
2194{
2195 Q_D(const QTextEdit);
2196 return d->control->currentCharFormat();
2197}
2198
2199/*!
2200 \property QTextEdit::autoFormatting
2201 \brief the enabled set of auto formatting features
2202
2203 The value can be any combination of the values in the
2204 AutoFormattingFlag enum. The default is AutoNone. Choose
2205 AutoAll to enable all automatic formatting.
2206
2207 Currently, the only automatic formatting feature provided is
2208 AutoBulletList; future versions of Qt may offer more.
2209*/
2210
2211QTextEdit::AutoFormatting QTextEdit::autoFormatting() const
2212{
2213 Q_D(const QTextEdit);
2214 return d->autoFormatting;
2215}
2216
2217void QTextEdit::setAutoFormatting(AutoFormatting features)
2218{
2219 Q_D(QTextEdit);
2220 d->autoFormatting = features;
2221}
2222
2223/*!
2224 Convenience slot that inserts \a text at the current
2225 cursor position.
2226
2227 It is equivalent to
2228
2229 \snippet code/src_gui_widgets_qtextedit.cpp 1
2230 */
2231void QTextEdit::insertPlainText(const QString &text)
2232{
2233 Q_D(QTextEdit);
2234 d->control->insertPlainText(text);
2235}
2236
2237/*!
2238 Convenience slot that inserts \a text which is assumed to be of
2239 html formatting at the current cursor position.
2240
2241 It is equivalent to:
2242
2243 \snippet code/src_gui_widgets_qtextedit.cpp 2
2244
2245 \note When using this function with a style sheet, the style sheet will
2246 only apply to the current block in the document. In order to apply a style
2247 sheet throughout a document, use QTextDocument::setDefaultStyleSheet()
2248 instead.
2249 */
2250#ifndef QT_NO_TEXTHTMLPARSER
2251void QTextEdit::insertHtml(const QString &text)
2252{
2253 Q_D(QTextEdit);
2254 d->control->insertHtml(text);
2255}
2256#endif // QT_NO_TEXTHTMLPARSER
2257
2258/*!
2259 Scrolls the text edit so that the anchor with the given \a name is
2260 visible; does nothing if the \a name is empty, or is already
2261 visible, or isn't found.
2262*/
2263void QTextEdit::scrollToAnchor(const QString &name)
2264{
2265 Q_D(QTextEdit);
2266 if (name.isEmpty())
2267 return;
2268
2269 if (!isVisible()) {
2270 d->anchorToScrollToWhenVisible = name;
2271 return;
2272 }
2273
2274 QPointF p = d->control->anchorPosition(name);
2275 const int newPosition = qRound(p.y());
2276 if ( d->vbar->maximum() < newPosition )
2277 d->adjustScrollbars();
2278 d->vbar->setValue(newPosition);
2279}
2280
2281/*!
2282 Zooms in on the text by making the base font size \a range
2283 points larger and recalculating all font sizes to be the new size.
2284 This does not change the size of any images.
2285
2286 \sa zoomOut()
2287*/
2288void QTextEdit::zoomIn(int range)
2289{
2290 zoomInF(range);
2291}
2292
2293/*!
2294 Zooms out on the text by making the base font size \a range points
2295 smaller and recalculating all font sizes to be the new size. This
2296 does not change the size of any images.
2297
2298 \sa zoomIn()
2299*/
2300void QTextEdit::zoomOut(int range)
2301{
2302 zoomInF(-range);
2303}
2304
2305/*!
2306 \internal
2307*/
2308void QTextEdit::zoomInF(float range)
2309{
2310 if (range == 0.f)
2311 return;
2312 QFont f = font();
2313 const float newSize = f.pointSizeF() + range;
2314 if (newSize <= 0)
2315 return;
2316 f.setPointSizeF(newSize);
2317 setFont(f);
2318}
2319
2320/*!
2321 \since 4.2
2322 Moves the cursor by performing the given \a operation.
2323
2324 If \a mode is QTextCursor::KeepAnchor, the cursor selects the text it moves over.
2325 This is the same effect that the user achieves when they hold down the Shift key
2326 and move the cursor with the cursor keys.
2327
2328 \sa QTextCursor::movePosition()
2329*/
2330void QTextEdit::moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode)
2331{
2332 Q_D(QTextEdit);
2333 d->control->moveCursor(operation, mode);
2334}
2335
2336/*!
2337 \since 4.2
2338 Returns whether text can be pasted from the clipboard into the textedit.
2339*/
2340bool QTextEdit::canPaste() const
2341{
2342 Q_D(const QTextEdit);
2343 return d->control->canPaste();
2344}
2345
2346/*!
2347 \since 4.3
2348 Convenience function to print the text edit's document to the given \a printer. This
2349 is equivalent to calling the print method on the document directly except that this
2350 function also supports QPrinter::Selection as print range.
2351
2352 \sa QTextDocument::print()
2353*/
2354#ifndef QT_NO_PRINTER
2355void QTextEdit::print(QPagedPaintDevice *printer) const
2356{
2357 Q_D(const QTextEdit);
2358 d->control->print(printer);
2359}
2360#endif
2361
2362/*! \property QTextEdit::tabChangesFocus
2363 \brief whether \uicontrol Tab changes focus or is accepted as input
2364
2365 In some occasions text edits should not allow the user to input
2366 tabulators or change indentation using the \uicontrol Tab key, as this breaks
2367 the focus chain. The default is false.
2368
2369*/
2370
2371bool QTextEdit::tabChangesFocus() const
2372{
2373 Q_D(const QTextEdit);
2374 return d->tabChangesFocus;
2375}
2376
2377void QTextEdit::setTabChangesFocus(bool b)
2378{
2379 Q_D(QTextEdit);
2380 d->tabChangesFocus = b;
2381}
2382
2383/*!
2384 \property QTextEdit::documentTitle
2385 \brief the title of the document parsed from the text.
2386
2387 By default, for a newly-created, empty document, this property contains
2388 an empty string.
2389*/
2390
2391/*!
2392 \property QTextEdit::lineWrapMode
2393 \brief the line wrap mode
2394
2395 The default mode is WidgetWidth which causes words to be
2396 wrapped at the right edge of the text edit. Wrapping occurs at
2397 whitespace, keeping whole words intact. If you want wrapping to
2398 occur within words use setWordWrapMode(). If you set a wrap mode of
2399 FixedPixelWidth or FixedColumnWidth you should also call
2400 setLineWrapColumnOrWidth() with the width you want.
2401
2402 \sa lineWrapColumnOrWidth
2403*/
2404
2405QTextEdit::LineWrapMode QTextEdit::lineWrapMode() const
2406{
2407 Q_D(const QTextEdit);
2408 return d->lineWrap;
2409}
2410
2411void QTextEdit::setLineWrapMode(LineWrapMode wrap)
2412{
2413 Q_D(QTextEdit);
2414 if (d->lineWrap == wrap)
2415 return;
2416 d->lineWrap = wrap;
2417 d->updateDefaultTextOption();
2418 d->relayoutDocument();
2419}
2420
2421/*!
2422 \property QTextEdit::lineWrapColumnOrWidth
2423 \brief the position (in pixels or columns depending on the wrap mode) where text will be wrapped
2424
2425 If the wrap mode is FixedPixelWidth, the value is the number of
2426 pixels from the left edge of the text edit at which text should be
2427 wrapped. If the wrap mode is FixedColumnWidth, the value is the
2428 column number (in character columns) from the left edge of the
2429 text edit at which text should be wrapped.
2430
2431 By default, this property contains a value of 0.
2432
2433 \sa lineWrapMode
2434*/
2435
2436int QTextEdit::lineWrapColumnOrWidth() const
2437{
2438 Q_D(const QTextEdit);
2439 return d->lineWrapColumnOrWidth;
2440}
2441
2442void QTextEdit::setLineWrapColumnOrWidth(int w)
2443{
2444 Q_D(QTextEdit);
2445 d->lineWrapColumnOrWidth = w;
2446 d->relayoutDocument();
2447}
2448
2449/*!
2450 \property QTextEdit::wordWrapMode
2451 \brief the mode QTextEdit will use when wrapping text by words
2452
2453 By default, this property is set to QTextOption::WrapAtWordBoundaryOrAnywhere.
2454
2455 \sa QTextOption::WrapMode
2456*/
2457
2458QTextOption::WrapMode QTextEdit::wordWrapMode() const
2459{
2460 Q_D(const QTextEdit);
2461 return d->wordWrap;
2462}
2463
2464void QTextEdit::setWordWrapMode(QTextOption::WrapMode mode)
2465{
2466 Q_D(QTextEdit);
2467 if (mode == d->wordWrap)
2468 return;
2469 d->wordWrap = mode;
2470 d->updateDefaultTextOption();
2471}
2472
2473/*!
2474 Finds the next occurrence of the string, \a exp, using the given
2475 \a options. Returns \c true if \a exp was found and changes the
2476 cursor to select the match; otherwise returns \c false.
2477*/
2478bool QTextEdit::find(const QString &exp, QTextDocument::FindFlags options)
2479{
2480 Q_D(QTextEdit);
2481 return d->control->find(exp, options);
2482}
2483
2484/*!
2485 \fn bool QTextEdit::find(const QRegularExpression &exp, QTextDocument::FindFlags options)
2486
2487 \since 5.13
2488 \overload
2489
2490 Finds the next occurrence, matching the regular expression, \a exp, using the given
2491 \a options.
2492
2493 Returns \c true if a match was found and changes the cursor to select the match;
2494 otherwise returns \c false.
2495
2496 \warning For historical reasons, the case sensitivity option set on
2497 \a exp is ignored. Instead, the \a options are used to determine
2498 if the search is case sensitive or not.
2499*/
2500#if QT_CONFIG(regularexpression)
2501bool QTextEdit::find(const QRegularExpression &exp, QTextDocument::FindFlags options)
2502{
2503 Q_D(QTextEdit);
2504 return d->control->find(exp, options);
2505}
2506#endif
2507
2508/*!
2509 \fn void QTextEdit::copyAvailable(bool yes)
2510
2511 This signal is emitted when text is selected or de-selected in the
2512 text edit.
2513
2514 When text is selected this signal will be emitted with \a yes set
2515 to true. If no text has been selected or if the selected text is
2516 de-selected this signal is emitted with \a yes set to false.
2517
2518 If \a yes is true then copy() can be used to copy the selection to
2519 the clipboard. If \a yes is false then copy() does nothing.
2520
2521 \sa selectionChanged()
2522*/
2523
2524/*!
2525 \fn void QTextEdit::currentCharFormatChanged(const QTextCharFormat &f)
2526
2527 This signal is emitted if the current character format has changed, for
2528 example caused by a change of the cursor position.
2529
2530 The new format is \a f.
2531
2532 \sa setCurrentCharFormat()
2533*/
2534
2535/*!
2536 \fn void QTextEdit::selectionChanged()
2537
2538 This signal is emitted whenever the selection changes.
2539
2540 \sa copyAvailable()
2541*/
2542
2543/*!
2544 \fn void QTextEdit::cursorPositionChanged()
2545
2546 This signal is emitted whenever the position of the
2547 cursor changed.
2548*/
2549
2550/*!
2551 \since 4.2
2552
2553 Sets the text edit's \a text. The text can be plain text or HTML
2554 and the text edit will try to guess the right format.
2555
2556 Use setHtml() or setPlainText() directly to avoid text edit's guessing.
2557
2558 \sa toPlainText(), toHtml()
2559*/
2560void QTextEdit::setText(const QString &text)
2561{
2562 Qt::TextFormat format = Qt::mightBeRichText(text) ? Qt::RichText : Qt::PlainText;
2563#ifndef QT_NO_TEXTHTMLPARSER
2564 if (format == Qt::RichText)
2565 setHtml(text);
2566 else
2567#else
2568 Q_UNUSED(format);
2569#endif
2570 setPlainText(text);
2571}
2572
2573
2574/*!
2575 Appends a new paragraph with \a text to the end of the text edit.
2576
2577 \note The new paragraph appended will have the same character format and
2578 block format as the current paragraph, determined by the position of the cursor.
2579
2580 \sa currentCharFormat(), QTextCursor::blockFormat()
2581*/
2582
2583void QTextEdit::append(const QString &text)
2584{
2585 Q_D(QTextEdit);
2586 const bool atBottom = isReadOnly() ? d->verticalOffset() >= d->vbar->maximum() :
2587 d->control->textCursor().atEnd();
2588 d->control->append(text);
2589 if (atBottom)
2590 d->vbar->setValue(d->vbar->maximum());
2591}
2592
2593/*!
2594 Ensures that the cursor is visible by scrolling the text edit if
2595 necessary.
2596*/
2597void QTextEdit::ensureCursorVisible()
2598{
2599 Q_D(QTextEdit);
2600 d->control->ensureCursorVisible();
2601}
2602
2603/*!
2604 \fn void QTextEdit::textChanged()
2605
2606 This signal is emitted whenever the document's content changes; for
2607 example, when text is inserted or deleted, or when formatting is applied.
2608*/
2609
2610/*!
2611 \fn void QTextEdit::undoAvailable(bool available)
2612
2613 This signal is emitted whenever undo operations become available
2614 (\a available is true) or unavailable (\a available is false).
2615*/
2616
2617/*!
2618 \fn void QTextEdit::redoAvailable(bool available)
2619
2620 This signal is emitted whenever redo operations become available
2621 (\a available is true) or unavailable (\a available is false).
2622*/
2623
2624QT_END_NAMESPACE
2625
2626#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
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE bool shouldEnableInputMethod(QTextEdit *textedit)
Definition qtextedit.cpp:45