1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextedit_p.h"
43 #include "qquicktextedit_p_p.h"
44 #include "qquicktextcontrol_p.h"
45 #include "qquicktext_p_p.h"
46 #include "qquickevents_p_p.h"
47 #include "qquickwindow.h"
48 #include "qquicktextnode_p.h"
49 #include "qquicktextutil_p.h"
50 #include <QtQuick/qsgsimplerectnode.h>
52 #include <QtQml/qqmlinfo.h>
53 #include <QtGui/qguiapplication.h>
54 #include <QtGui/qevent.h>
55 #include <QtGui/qpainter.h>
56 #include <QtGui/qtextobject.h>
57 #include <QtCore/qmath.h>
59 #include <private/qqmlglobal_p.h>
60 #include <private/qqmlproperty_p.h>
61 #include <private/qtextengine_p.h>
62 #include <private/qsgadaptationlayer_p.h>
68 \qmlclass TextEdit QQuickTextEdit
69 \inqmlmodule QtQuick 2
70 \ingroup qtquick-visual
71 \ingroup qtquick-input
73 \brief Displays multiple lines of editable formatted text
75 The TextEdit item displays a block of editable, formatted text.
77 It can display both plain and rich text. For example:
82 text: "<b>Hello</b> <i>World!</i>"
83 font.family: "Helvetica"
90 \image declarative-textedit.gif
92 Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
94 Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
95 to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
97 \snippet qml/texteditor.qml 0
99 A particular look-and-feel might use smooth scrolling (eg. using SmoothedAnimation), might have a visible
100 scrollbar, or a scrollbar that fades in to show location, etc.
102 Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
103 be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
104 from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
106 You can translate between cursor positions (characters from the start of the document) and pixel
107 points using positionAt() and positionToRectangle().
109 \sa Text, TextInput, {examples/quick/text/textselection}{Text Selection example}
113 \qmlsignal QtQuick2::TextEdit::onLinkActivated(string link)
115 This handler is called when the user clicks on a link embedded in the text.
116 The link must be in rich text or HTML format and the
117 \a link string provides access to the particular link.
119 QQuickTextEdit::QQuickTextEdit(QQuickItem *parent)
120 : QQuickImplicitSizeItem(*(new QQuickTextEditPrivate), parent)
126 QString QQuickTextEdit::text() const
128 Q_D(const QQuickTextEdit);
129 if (!d->textCached) {
130 QQuickTextEditPrivate *d = const_cast<QQuickTextEditPrivate *>(d_func());
131 #ifndef QT_NO_TEXTHTMLPARSER
133 d->text = d->control->toHtml();
136 d->text = d->control->toPlainText();
137 d->textCached = true;
143 \qmlproperty string QtQuick2::TextEdit::font.family
145 Sets the family name of the font.
147 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
148 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
149 If the family isn't available a family will be set using the font matching algorithm.
153 \qmlproperty bool QtQuick2::TextEdit::font.bold
155 Sets whether the font weight is bold.
159 \qmlproperty enumeration QtQuick2::TextEdit::font.weight
161 Sets the font's weight.
163 The weight can be one of:
166 \li Font.Normal - the default
173 TextEdit { text: "Hello"; font.weight: Font.DemiBold }
178 \qmlproperty bool QtQuick2::TextEdit::font.italic
180 Sets whether the font has an italic style.
184 \qmlproperty bool QtQuick2::TextEdit::font.underline
186 Sets whether the text is underlined.
190 \qmlproperty bool QtQuick2::TextEdit::font.strikeout
192 Sets whether the font has a strikeout style.
196 \qmlproperty real QtQuick2::TextEdit::font.pointSize
198 Sets the font size in points. The point size must be greater than zero.
202 \qmlproperty int QtQuick2::TextEdit::font.pixelSize
204 Sets the font size in pixels.
206 Using this function makes the font device dependent. Use
207 \l{TextEdit::font.pointSize} to set the size of the font in a
208 device independent manner.
212 \qmlproperty real QtQuick2::TextEdit::font.letterSpacing
214 Sets the letter spacing for the font.
216 Letter spacing changes the default spacing between individual letters in the font.
217 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
221 \qmlproperty real QtQuick2::TextEdit::font.wordSpacing
223 Sets the word spacing for the font.
225 Word spacing changes the default spacing between individual words.
226 A positive value increases the word spacing by a corresponding amount of pixels,
227 while a negative value decreases the inter-word spacing accordingly.
231 \qmlproperty enumeration QtQuick2::TextEdit::font.capitalization
233 Sets the capitalization for the text.
236 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
237 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
238 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
239 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
240 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
244 TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
249 \qmlproperty string QtQuick2::TextEdit::text
251 The text to display. If the text format is AutoText the text edit will
252 automatically determine whether the text should be treated as
253 rich text. This determination is made using Qt::mightBeRichText().
255 void QQuickTextEdit::setText(const QString &text)
258 if (QQuickTextEdit::text() == text)
261 d->document->clearResources();
262 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
263 if (!isComponentComplete()) {
265 } else if (d->richText) {
266 #ifndef QT_NO_TEXTHTMLPARSER
267 d->control->setHtml(text);
269 d->control->setPlainText(text);
272 d->control->setPlainText(text);
277 \qmlproperty enumeration QtQuick2::TextEdit::textFormat
279 The way the text property should be displayed.
282 \li TextEdit.AutoText
283 \li TextEdit.PlainText
284 \li TextEdit.RichText
287 The default is TextEdit.PlainText. If the text format is TextEdit.AutoText the text edit
288 will automatically determine whether the text should be treated as
289 rich text. This determination is made using Qt::mightBeRichText().
298 text: "<b>Hello</b> <i>World!</i>"
302 textFormat: TextEdit.RichText
303 text: "<b>Hello</b> <i>World!</i>"
307 textFormat: TextEdit.PlainText
308 text: "<b>Hello</b> <i>World!</i>"
312 \li \image declarative-textformat.png
315 QQuickTextEdit::TextFormat QQuickTextEdit::textFormat() const
317 Q_D(const QQuickTextEdit);
321 void QQuickTextEdit::setTextFormat(TextFormat format)
324 if (format == d->format)
327 bool wasRich = d->richText;
328 d->richText = format == RichText || (format == AutoText && (wasRich || Qt::mightBeRichText(text())));
330 #ifndef QT_NO_TEXTHTMLPARSER
331 if (isComponentComplete()) {
332 if (wasRich && !d->richText) {
333 d->control->setPlainText(!d->textCached ? d->control->toHtml() : d->text);
335 } else if (!wasRich && d->richText) {
336 d->control->setHtml(!d->textCached ? d->control->toPlainText() : d->text);
343 d->control->setAcceptRichText(d->format != PlainText);
344 emit textFormatChanged(d->format);
348 \qmlproperty enumeration QtQuick2::TextEdit::renderType
350 Override the default rendering type for this component.
352 Supported render types are:
354 \li Text.QtRendering - the default
355 \li Text.NativeRendering
358 Select Text.NativeRendering if you prefer text to look native on the target platform and do
359 not require advanced features such as transformation of the text. Using such features in
360 combination with the NativeRendering render type will lend poor and sometimes pixelated
363 QQuickTextEdit::RenderType QQuickTextEdit::renderType() const
365 Q_D(const QQuickTextEdit);
366 return d->renderType;
369 void QQuickTextEdit::setRenderType(QQuickTextEdit::RenderType renderType)
372 if (d->renderType == renderType)
375 d->renderType = renderType;
376 emit renderTypeChanged();
377 d->updateDefaultTextOption();
379 if (isComponentComplete())
383 QFont QQuickTextEdit::font() const
385 Q_D(const QQuickTextEdit);
386 return d->sourceFont;
389 void QQuickTextEdit::setFont(const QFont &font)
392 if (d->sourceFont == font)
395 d->sourceFont = font;
396 QFont oldFont = d->font;
398 if (d->font.pointSizeF() != -1) {
400 qreal size = qRound(d->font.pointSizeF()*2.0);
401 d->font.setPointSizeF(size/2.0);
404 if (oldFont != d->font) {
405 d->document->setDefaultFont(d->font);
407 d->cursorItem->setHeight(QFontMetrics(d->font).height());
408 moveCursorDelegate();
412 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
414 emit fontChanged(d->sourceFont);
418 \qmlproperty color QtQuick2::TextEdit::color
423 // green text using hexadecimal notation
424 TextEdit { color: "#00FF00" }
428 // steelblue text using SVG color name
429 TextEdit { color: "steelblue" }
432 QColor QQuickTextEdit::color() const
434 Q_D(const QQuickTextEdit);
438 void QQuickTextEdit::setColor(const QColor &color)
441 if (d->color == color)
446 emit colorChanged(d->color);
450 \qmlproperty color QtQuick2::TextEdit::selectionColor
452 The text highlight color, used behind selections.
454 QColor QQuickTextEdit::selectionColor() const
456 Q_D(const QQuickTextEdit);
457 return d->selectionColor;
460 void QQuickTextEdit::setSelectionColor(const QColor &color)
463 if (d->selectionColor == color)
466 d->selectionColor = color;
468 emit selectionColorChanged(d->selectionColor);
472 \qmlproperty color QtQuick2::TextEdit::selectedTextColor
474 The selected text color, used in selections.
476 QColor QQuickTextEdit::selectedTextColor() const
478 Q_D(const QQuickTextEdit);
479 return d->selectedTextColor;
482 void QQuickTextEdit::setSelectedTextColor(const QColor &color)
485 if (d->selectedTextColor == color)
488 d->selectedTextColor = color;
490 emit selectedTextColorChanged(d->selectedTextColor);
494 \qmlproperty enumeration QtQuick2::TextEdit::horizontalAlignment
495 \qmlproperty enumeration QtQuick2::TextEdit::verticalAlignment
496 \qmlproperty enumeration QtQuick2::TextEdit::effectiveHorizontalAlignment
498 Sets the horizontal and vertical alignment of the text within the TextEdit item's
499 width and height. By default, the text alignment follows the natural alignment
500 of the text, for example text that is read from left to right will be aligned to
503 Valid values for \c horizontalAlignment are:
505 \li TextEdit.AlignLeft (default)
506 \li TextEdit.AlignRight
507 \li TextEdit.AlignHCenter
508 \li TextEdit.AlignJustify
511 Valid values for \c verticalAlignment are:
513 \li TextEdit.AlignTop (default)
514 \li TextEdit.AlignBottom
515 \li TextEdit.AlignVCenter
518 When using the attached property LayoutMirroring::enabled to mirror application
519 layouts, the horizontal alignment of text will also be mirrored. However, the property
520 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
521 of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
523 QQuickTextEdit::HAlignment QQuickTextEdit::hAlign() const
525 Q_D(const QQuickTextEdit);
529 void QQuickTextEdit::setHAlign(HAlignment align)
532 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
533 d->hAlignImplicit = false;
534 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
535 d->updateDefaultTextOption();
540 void QQuickTextEdit::resetHAlign()
543 d->hAlignImplicit = true;
544 if (d->determineHorizontalAlignment() && isComponentComplete()) {
545 d->updateDefaultTextOption();
550 QQuickTextEdit::HAlignment QQuickTextEdit::effectiveHAlign() const
552 Q_D(const QQuickTextEdit);
553 QQuickTextEdit::HAlignment effectiveAlignment = d->hAlign;
554 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
556 case QQuickTextEdit::AlignLeft:
557 effectiveAlignment = QQuickTextEdit::AlignRight;
559 case QQuickTextEdit::AlignRight:
560 effectiveAlignment = QQuickTextEdit::AlignLeft;
566 return effectiveAlignment;
569 bool QQuickTextEditPrivate::setHAlign(QQuickTextEdit::HAlignment alignment, bool forceAlign)
572 if (hAlign != alignment || forceAlign) {
573 QQuickTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
575 emit q->horizontalAlignmentChanged(alignment);
576 if (oldEffectiveHAlign != q->effectiveHAlign())
577 emit q->effectiveHorizontalAlignmentChanged();
584 Qt::LayoutDirection QQuickTextEditPrivate::textDirection(const QString &text) const
586 const QChar *character = text.constData();
587 while (!character->isNull()) {
588 switch (character->direction()) {
590 return Qt::LeftToRight;
594 return Qt::RightToLeft;
600 return Qt::LayoutDirectionAuto;
603 bool QQuickTextEditPrivate::determineHorizontalAlignment()
606 if (hAlignImplicit && q->isComponentComplete()) {
607 Qt::LayoutDirection direction = contentDirection;
608 if (direction == Qt::LayoutDirectionAuto) {
609 const QString preeditText = control->textCursor().block().layout()->preeditAreaText();
610 direction = textDirection(preeditText);
612 if (direction == Qt::LayoutDirectionAuto)
613 direction = qGuiApp->inputMethod()->inputDirection();
615 return setHAlign(direction == Qt::RightToLeft ? QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft);
620 void QQuickTextEditPrivate::mirrorChange()
623 if (q->isComponentComplete()) {
624 if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) {
625 updateDefaultTextOption();
627 emit q->effectiveHorizontalAlignmentChanged();
632 QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const
634 Q_D(const QQuickTextEdit);
638 void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment)
641 if (alignment == d->vAlign)
643 d->vAlign = alignment;
644 d->updateDefaultTextOption();
646 moveCursorDelegate();
647 emit verticalAlignmentChanged(d->vAlign);
650 \qmlproperty enumeration QtQuick2::TextEdit::wrapMode
652 Set this property to wrap the text to the TextEdit item's width.
653 The text will only wrap if an explicit width has been set.
656 \li TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
657 \li TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
658 \li TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
659 \li TextEdit.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
662 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
664 QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode() const
666 Q_D(const QQuickTextEdit);
670 void QQuickTextEdit::setWrapMode(WrapMode mode)
673 if (mode == d->wrapMode)
676 d->updateDefaultTextOption();
678 emit wrapModeChanged();
682 \qmlproperty int QtQuick2::TextEdit::lineCount
684 Returns the total number of lines in the textEdit item.
686 int QQuickTextEdit::lineCount() const
688 Q_D(const QQuickTextEdit);
693 \qmlproperty int QtQuick2::TextEdit::length
695 Returns the total number of plain text characters in the TextEdit item.
697 As this number doesn't include any formatting markup it may not be the same as the
698 length of the string returned by the \l text property.
700 This property can be faster than querying the length the \l text property as it doesn't
701 require any copying or conversion of the TextEdit's internal string data.
704 int QQuickTextEdit::length() const
706 Q_D(const QQuickTextEdit);
707 // QTextDocument::characterCount() includes the terminating null character.
708 return qMax(0, d->document->characterCount() - 1);
712 \qmlproperty real QtQuick2::TextEdit::contentWidth
714 Returns the width of the text, including the width past the width
715 which is covered due to insufficient wrapping if \l wrapMode is set.
717 qreal QQuickTextEdit::contentWidth() const
719 Q_D(const QQuickTextEdit);
720 return d->contentSize.width();
724 \qmlproperty real QtQuick2::TextEdit::contentHeight
726 Returns the height of the text, including the height past the height
727 that is covered if the text does not fit within the set height.
729 qreal QQuickTextEdit::contentHeight() const
731 Q_D(const QQuickTextEdit);
732 return d->contentSize.height();
736 \qmlproperty url QtQuick2::TextEdit::baseUrl
738 This property specifies a base URL which is used to resolve relative URLs
741 The default value is the url of the QML file instantiating the TextEdit item.
744 QUrl QQuickTextEdit::baseUrl() const
746 Q_D(const QQuickTextEdit);
747 if (d->baseUrl.isEmpty()) {
748 if (QQmlContext *context = qmlContext(this))
749 const_cast<QQuickTextEditPrivate *>(d)->baseUrl = context->baseUrl();
754 void QQuickTextEdit::setBaseUrl(const QUrl &url)
757 if (baseUrl() != url) {
760 d->document->setBaseUrl(url, d->richText);
761 emit baseUrlChanged();
765 void QQuickTextEdit::resetBaseUrl()
767 if (QQmlContext *context = qmlContext(this))
768 setBaseUrl(context->baseUrl());
774 \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position)
776 Returns the rectangle at the given \a position in the text. The x, y,
777 and height properties correspond to the cursor that would describe
780 QRectF QQuickTextEdit::positionToRectangle(int pos) const
782 Q_D(const QQuickTextEdit);
783 QTextCursor c(d->document);
785 return d->control->cursorRect(c).translated(d->xoff, d->yoff);
790 \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y)
792 Returns the text position closest to pixel position (\a x, \a y).
794 Position 0 is before the first character, position 1 is after the first character
795 but before the second, and so on until position \l {text}.length, which is after all characters.
797 int QQuickTextEdit::positionAt(qreal x, qreal y) const
799 Q_D(const QQuickTextEdit);
803 int r = d->document->documentLayout()->hitTest(QPointF(x, y), Qt::FuzzyHit);
804 QTextCursor cursor = d->control->textCursor();
805 if (r > cursor.position()) {
806 // The cursor position includes positions within the preedit text, but only positions in the
807 // same text block are offset so it is possible to get a position that is either part of the
808 // preedit or the next text block.
809 QTextLayout *layout = cursor.block().layout();
810 const int preeditLength = layout
811 ? layout->preeditAreaText().length()
813 if (preeditLength > 0
814 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x, y)) {
815 r = r > cursor.position() + preeditLength
824 \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
826 Moves the cursor to \a position and updates the selection according to the optional \a mode
827 parameter. (To only move the cursor, set the \l cursorPosition property.)
829 When this method is called it additionally sets either the
830 selectionStart or the selectionEnd (whichever was at the previous cursor position)
831 to the specified position. This allows you to easily extend and contract the selected
834 The selection mode specifies whether the selection is updated on a per character or a per word
835 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
838 \li TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
839 the previous cursor position) to the specified position.
840 \li TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
841 words between the specified position and the previous cursor position. Words partially in the
845 For example, take this sequence of calls:
849 moveCursorSelection(9, TextEdit.SelectCharacters)
850 moveCursorSelection(7, TextEdit.SelectCharacters)
853 This moves the cursor to position 5, extend the selection end from 5 to 9
854 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
855 selected (the 6th and 7th characters).
857 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
858 before or on position 5 and extend the selection end to a word boundary on or past position 9.
860 void QQuickTextEdit::moveCursorSelection(int pos)
862 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
864 QTextCursor cursor = d->control->textCursor();
865 if (cursor.position() == pos)
867 cursor.setPosition(pos, QTextCursor::KeepAnchor);
868 d->control->setTextCursor(cursor);
871 void QQuickTextEdit::moveCursorSelection(int pos, SelectionMode mode)
874 QTextCursor cursor = d->control->textCursor();
875 if (cursor.position() == pos)
877 if (mode == SelectCharacters) {
878 cursor.setPosition(pos, QTextCursor::KeepAnchor);
879 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
880 if (cursor.anchor() > cursor.position()) {
881 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
882 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
883 if (cursor.position() == cursor.anchor())
884 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
886 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
888 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
889 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
892 cursor.setPosition(pos, QTextCursor::KeepAnchor);
893 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
894 if (cursor.position() != pos)
895 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
896 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
897 if (cursor.anchor() < cursor.position()) {
898 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
899 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
901 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
902 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
903 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
904 if (cursor.position() != cursor.anchor()) {
905 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
906 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
910 cursor.setPosition(pos, QTextCursor::KeepAnchor);
911 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
912 if (cursor.position() != pos) {
913 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
914 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
917 d->control->setTextCursor(cursor);
921 \qmlproperty bool QtQuick2::TextEdit::cursorVisible
922 If true the text edit shows a cursor.
924 This property is set and unset when the text edit gets active focus, but it can also
925 be set directly (useful, for example, if a KeyProxy might forward keys to it).
927 bool QQuickTextEdit::isCursorVisible() const
929 Q_D(const QQuickTextEdit);
930 return d->cursorVisible;
933 void QQuickTextEdit::setCursorVisible(bool on)
936 if (d->cursorVisible == on)
938 d->cursorVisible = on;
939 if (on && isComponentComplete())
940 QQuickTextUtil::createCursor(d);
941 if (!on && !d->persistentSelection)
942 d->control->setCursorIsFocusIndicator(true);
943 d->control->setCursorVisible(on);
944 emit cursorVisibleChanged(d->cursorVisible);
948 \qmlproperty int QtQuick2::TextEdit::cursorPosition
949 The position of the cursor in the TextEdit.
951 int QQuickTextEdit::cursorPosition() const
953 Q_D(const QQuickTextEdit);
954 return d->control->textCursor().position();
957 void QQuickTextEdit::setCursorPosition(int pos)
960 if (pos < 0 || pos >= d->document->characterCount()) // characterCount includes the terminating null.
962 QTextCursor cursor = d->control->textCursor();
963 if (cursor.position() == pos && cursor.anchor() == pos)
965 cursor.setPosition(pos);
966 d->control->setTextCursor(cursor);
967 d->control->updateCursorRectangle(true);
971 \qmlproperty Component QtQuick2::TextEdit::cursorDelegate
972 The delegate for the cursor in the TextEdit.
974 If you set a cursorDelegate for a TextEdit, this delegate will be used for
975 drawing the cursor instead of the standard cursor. An instance of the
976 delegate will be created and managed by the text edit when a cursor is
977 needed, and the x and y properties of delegate instance will be set so as
978 to be one pixel before the top left of the current character.
980 Note that the root item of the delegate component must be a QQuickItem or
981 QQuickItem derived item.
983 QQmlComponent* QQuickTextEdit::cursorDelegate() const
985 Q_D(const QQuickTextEdit);
986 return d->cursorComponent;
989 void QQuickTextEdit::setCursorDelegate(QQmlComponent* c)
992 QQuickTextUtil::setCursorDelegate(d, c);
995 void QQuickTextEdit::createCursor()
998 d->cursorPending = true;
999 QQuickTextUtil::createCursor(d);
1003 \qmlproperty int QtQuick2::TextEdit::selectionStart
1005 The cursor position before the first character in the current selection.
1007 This property is read-only. To change the selection, use select(start,end),
1008 selectAll(), or selectWord().
1010 \sa selectionEnd, cursorPosition, selectedText
1012 int QQuickTextEdit::selectionStart() const
1014 Q_D(const QQuickTextEdit);
1015 return d->control->textCursor().selectionStart();
1019 \qmlproperty int QtQuick2::TextEdit::selectionEnd
1021 The cursor position after the last character in the current selection.
1023 This property is read-only. To change the selection, use select(start,end),
1024 selectAll(), or selectWord().
1026 \sa selectionStart, cursorPosition, selectedText
1028 int QQuickTextEdit::selectionEnd() const
1030 Q_D(const QQuickTextEdit);
1031 return d->control->textCursor().selectionEnd();
1035 \qmlproperty string QtQuick2::TextEdit::selectedText
1037 This read-only property provides the text currently selected in the
1040 It is equivalent to the following snippet, but is faster and easier
1043 //myTextEdit is the id of the TextEdit
1044 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
1045 myTextEdit.selectionEnd);
1048 QString QQuickTextEdit::selectedText() const
1050 Q_D(const QQuickTextEdit);
1051 #ifndef QT_NO_TEXTHTMLPARSER
1053 ? d->control->textCursor().selectedText()
1054 : d->control->textCursor().selection().toPlainText();
1056 return d->control->textCursor().selection().toPlainText();
1061 \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress
1063 Whether the TextEdit should gain active focus on a mouse press. By default this is
1066 bool QQuickTextEdit::focusOnPress() const
1068 Q_D(const QQuickTextEdit);
1069 return d->focusOnPress;
1072 void QQuickTextEdit::setFocusOnPress(bool on)
1074 Q_D(QQuickTextEdit);
1075 if (d->focusOnPress == on)
1077 d->focusOnPress = on;
1078 emit activeFocusOnPressChanged(d->focusOnPress);
1082 \qmlproperty bool QtQuick2::TextEdit::persistentSelection
1084 Whether the TextEdit should keep the selection visible when it loses active focus to another
1085 item in the scene. By default this is set to true;
1087 bool QQuickTextEdit::persistentSelection() const
1089 Q_D(const QQuickTextEdit);
1090 return d->persistentSelection;
1093 void QQuickTextEdit::setPersistentSelection(bool on)
1095 Q_D(QQuickTextEdit);
1096 if (d->persistentSelection == on)
1098 d->persistentSelection = on;
1099 emit persistentSelectionChanged(d->persistentSelection);
1103 \qmlproperty real QtQuick2::TextEdit::textMargin
1105 The margin, in pixels, around the text in the TextEdit.
1107 qreal QQuickTextEdit::textMargin() const
1109 Q_D(const QQuickTextEdit);
1110 return d->textMargin;
1113 void QQuickTextEdit::setTextMargin(qreal margin)
1115 Q_D(QQuickTextEdit);
1116 if (d->textMargin == margin)
1118 d->textMargin = margin;
1119 d->document->setDocumentMargin(d->textMargin);
1120 emit textMarginChanged(d->textMargin);
1124 \qmlproperty enumeration QtQuick2::TextEdit::inputMethodHints
1126 Provides hints to the input method about the expected content of the text edit and how it
1129 The value is a bit-wise combination of flags or Qt.ImhNone if no hints are set.
1131 Flags that alter behaviour are:
1134 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1135 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1136 in any persistent storage like predictive user dictionary.
1137 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1138 when a sentence ends.
1139 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1140 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1141 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1142 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1144 \li Qt.ImhDate - The text editor functions as a date field.
1145 \li Qt.ImhTime - The text editor functions as a time field.
1148 Flags that restrict input (exclusive flags) are:
1151 \li Qt.ImhDigitsOnly - Only digits are allowed.
1152 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1153 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1154 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1155 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1156 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1157 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1163 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1167 Qt::InputMethodHints QQuickTextEdit::inputMethodHints() const
1169 Q_D(const QQuickTextEdit);
1170 return d->inputMethodHints;
1173 void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints)
1175 Q_D(QQuickTextEdit);
1177 if (hints == d->inputMethodHints)
1180 d->inputMethodHints = hints;
1181 updateInputMethod(Qt::ImHints);
1182 emit inputMethodHintsChanged();
1185 void QQuickTextEdit::geometryChanged(const QRectF &newGeometry,
1186 const QRectF &oldGeometry)
1188 Q_D(QQuickTextEdit);
1189 if (newGeometry.width() != oldGeometry.width() && widthValid() && !d->inLayout) {
1191 moveCursorDelegate();
1193 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1198 Ensures any delayed caching or data loading the class
1199 needs to performed is complete.
1201 void QQuickTextEdit::componentComplete()
1203 Q_D(QQuickTextEdit);
1204 QQuickImplicitSizeItem::componentComplete();
1206 d->document->setBaseUrl(baseUrl(), d->richText);
1207 #ifndef QT_NO_TEXTHTML_PARSER
1209 d->control->setHtml(d->text);
1212 if (!d->text.isEmpty())
1213 d->control->setPlainText(d->text);
1216 d->determineHorizontalAlignment();
1217 d->updateDefaultTextOption();
1221 if (d->cursorComponent && isCursorVisible())
1222 QQuickTextUtil::createCursor(d);
1225 \qmlproperty bool QtQuick2::TextEdit::selectByMouse
1229 If true, the user can use the mouse to select text in some
1230 platform-specific way. Note that for some platforms this may
1231 not be an appropriate interaction (eg. may conflict with how
1232 the text needs to behave inside a Flickable.
1234 bool QQuickTextEdit::selectByMouse() const
1236 Q_D(const QQuickTextEdit);
1237 return d->selectByMouse;
1240 void QQuickTextEdit::setSelectByMouse(bool on)
1242 Q_D(QQuickTextEdit);
1243 if (d->selectByMouse != on) {
1244 d->selectByMouse = on;
1245 setKeepMouseGrab(on);
1247 d->control->setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1249 d->control->setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1250 emit selectByMouseChanged(on);
1255 \qmlproperty enumeration QtQuick2::TextEdit::mouseSelectionMode
1257 Specifies how text should be selected using a mouse.
1260 \li TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1261 \li TextEdit.SelectWords - The selection is updated with whole words.
1264 This property only applies when \l selectByMouse is true.
1266 QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode() const
1268 Q_D(const QQuickTextEdit);
1269 return d->mouseSelectionMode;
1272 void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode)
1274 Q_D(QQuickTextEdit);
1275 if (d->mouseSelectionMode != mode) {
1276 d->mouseSelectionMode = mode;
1277 d->control->setWordSelectionEnabled(mode == SelectWords);
1278 emit mouseSelectionModeChanged(mode);
1283 \qmlproperty bool QtQuick2::TextEdit::readOnly
1285 Whether the user can interact with the TextEdit item. If this
1286 property is set to true the text cannot be edited by user interaction.
1288 By default this property is false.
1290 void QQuickTextEdit::setReadOnly(bool r)
1292 Q_D(QQuickTextEdit);
1293 if (r == isReadOnly())
1296 setFlag(QQuickItem::ItemAcceptsInputMethod, !r);
1297 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1298 if (d->selectByMouse)
1299 flags = flags | Qt::TextSelectableByMouse;
1301 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1302 d->control->setTextInteractionFlags(flags);
1304 d->control->moveCursor(QTextCursor::End);
1306 updateInputMethod(Qt::ImEnabled);
1307 q_canPasteChanged();
1308 emit readOnlyChanged(r);
1311 bool QQuickTextEdit::isReadOnly() const
1313 Q_D(const QQuickTextEdit);
1314 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1318 \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle
1320 The rectangle where the standard text cursor is rendered
1321 within the text edit. Read-only.
1323 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
1324 automatically when it changes. The width of the delegate is unaffected by changes in the
1327 QRectF QQuickTextEdit::cursorRectangle() const
1329 Q_D(const QQuickTextEdit);
1330 return d->control->cursorRect().translated(d->xoff, d->yoff);
1333 bool QQuickTextEdit::event(QEvent *event)
1335 Q_D(QQuickTextEdit);
1336 if (event->type() == QEvent::ShortcutOverride) {
1337 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1338 return event->isAccepted();
1340 return QQuickImplicitSizeItem::event(event);
1345 Handles the given key \a event.
1347 void QQuickTextEdit::keyPressEvent(QKeyEvent *event)
1349 Q_D(QQuickTextEdit);
1350 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1351 if (!event->isAccepted())
1352 QQuickImplicitSizeItem::keyPressEvent(event);
1357 Handles the given key \a event.
1359 void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event)
1361 Q_D(QQuickTextEdit);
1362 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1363 if (!event->isAccepted())
1364 QQuickImplicitSizeItem::keyReleaseEvent(event);
1368 \qmlmethod void QtQuick2::TextEdit::deselect()
1370 Removes active text selection.
1372 void QQuickTextEdit::deselect()
1374 Q_D(QQuickTextEdit);
1375 QTextCursor c = d->control->textCursor();
1377 d->control->setTextCursor(c);
1381 \qmlmethod void QtQuick2::TextEdit::selectAll()
1383 Causes all text to be selected.
1385 void QQuickTextEdit::selectAll()
1387 Q_D(QQuickTextEdit);
1388 d->control->selectAll();
1392 \qmlmethod void QtQuick2::TextEdit::selectWord()
1394 Causes the word closest to the current cursor position to be selected.
1396 void QQuickTextEdit::selectWord()
1398 Q_D(QQuickTextEdit);
1399 QTextCursor c = d->control->textCursor();
1400 c.select(QTextCursor::WordUnderCursor);
1401 d->control->setTextCursor(c);
1405 \qmlmethod void QtQuick2::TextEdit::select(int start, int end)
1407 Causes the text from \a start to \a end to be selected.
1409 If either start or end is out of range, the selection is not changed.
1411 After calling this, selectionStart will become the lesser
1412 and selectionEnd will become the greater (regardless of the order passed
1415 \sa selectionStart, selectionEnd
1417 void QQuickTextEdit::select(int start, int end)
1419 Q_D(QQuickTextEdit);
1420 if (start < 0 || end < 0 || start >= d->document->characterCount() || end >= d->document->characterCount())
1422 QTextCursor cursor = d->control->textCursor();
1423 cursor.beginEditBlock();
1424 cursor.setPosition(start, QTextCursor::MoveAnchor);
1425 cursor.setPosition(end, QTextCursor::KeepAnchor);
1426 cursor.endEditBlock();
1427 d->control->setTextCursor(cursor);
1430 updateSelectionMarkers();
1434 \qmlmethod void QtQuick2::TextEdit::isRightToLeft(int start, int end)
1436 Returns true if the natural reading direction of the editor text
1437 found between positions \a start and \a end is right to left.
1439 bool QQuickTextEdit::isRightToLeft(int start, int end)
1442 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1445 return getText(start, end).isRightToLeft();
1449 #ifndef QT_NO_CLIPBOARD
1451 \qmlmethod QtQuick2::TextEdit::cut()
1453 Moves the currently selected text to the system clipboard.
1455 void QQuickTextEdit::cut()
1457 Q_D(QQuickTextEdit);
1462 \qmlmethod QtQuick2::TextEdit::copy()
1464 Copies the currently selected text to the system clipboard.
1466 void QQuickTextEdit::copy()
1468 Q_D(QQuickTextEdit);
1473 \qmlmethod QtQuick2::TextEdit::paste()
1475 Replaces the currently selected text by the contents of the system clipboard.
1477 void QQuickTextEdit::paste()
1479 Q_D(QQuickTextEdit);
1480 d->control->paste();
1482 #endif // QT_NO_CLIPBOARD
1486 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1487 current selection, and updates the selection start to the current cursor
1491 void QQuickTextEdit::undo()
1493 Q_D(QQuickTextEdit);
1498 Redoes the last operation if redo is \l {canRedo}{available}.
1501 void QQuickTextEdit::redo()
1503 Q_D(QQuickTextEdit);
1509 Handles the given mouse \a event.
1511 void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
1513 Q_D(QQuickTextEdit);
1514 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1515 if (d->focusOnPress){
1516 bool hadActiveFocus = hasActiveFocus();
1518 // re-open input panel on press if already focused
1519 if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
1520 qGuiApp->inputMethod()->show();
1522 if (!event->isAccepted())
1523 QQuickImplicitSizeItem::mousePressEvent(event);
1528 Handles the given mouse \a event.
1530 void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
1532 Q_D(QQuickTextEdit);
1533 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1535 if (!event->isAccepted())
1536 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1541 Handles the given mouse \a event.
1543 void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
1545 Q_D(QQuickTextEdit);
1546 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1547 if (!event->isAccepted())
1548 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1553 Handles the given mouse \a event.
1555 void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
1557 Q_D(QQuickTextEdit);
1558 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1559 if (!event->isAccepted())
1560 QQuickImplicitSizeItem::mouseMoveEvent(event);
1565 Handles the given input method \a event.
1567 void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
1569 Q_D(QQuickTextEdit);
1570 const bool wasComposing = isInputMethodComposing();
1571 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1572 setCursorVisible(d->control->cursorVisible());
1573 if (wasComposing != isInputMethodComposing())
1574 emit inputMethodComposingChanged();
1577 void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1579 Q_D(QQuickTextEdit);
1580 if (change == ItemActiveFocusHasChanged) {
1581 setCursorVisible(value.boolValue);
1582 QFocusEvent focusEvent(value.boolValue ? QEvent::FocusIn : QEvent::FocusOut);
1583 d->control->processEvent(&focusEvent, QPointF(-d->xoff, -d->yoff));
1584 if (value.boolValue) {
1585 q_updateAlignment();
1586 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1587 this, SLOT(q_updateAlignment()));
1589 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1590 this, SLOT(q_updateAlignment()));
1593 QQuickItem::itemChange(change, value);
1598 Returns the value of the given \a property.
1600 QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1602 Q_D(const QQuickTextEdit);
1607 v = (bool)(flags() & ItemAcceptsInputMethod);
1610 v = (int)inputMethodHints();
1613 v = d->control->inputMethodQuery(property);
1620 void QQuickTextEdit::triggerPreprocess()
1622 Q_D(QQuickTextEdit);
1623 if (d->updateType == QQuickTextEditPrivate::UpdateNone)
1624 d->updateType = QQuickTextEditPrivate::UpdateOnlyPreprocess;
1628 QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1630 Q_UNUSED(updatePaintNodeData);
1631 Q_D(QQuickTextEdit);
1633 if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode && oldNode != 0) {
1634 // Update done in preprocess() in the nodes
1635 d->updateType = QQuickTextEditPrivate::UpdateNone;
1639 d->updateType = QQuickTextEditPrivate::UpdateNone;
1641 QSGNode *currentNode = oldNode;
1642 if (oldNode == 0 || d->documentDirty) {
1643 d->documentDirty = false;
1645 QQuickTextNode *node = 0;
1647 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1650 node = static_cast<QQuickTextNode *>(oldNode);
1653 node->setUseNativeRenderer(d->renderType == NativeRendering);
1654 node->deleteContent();
1655 node->setMatrix(QMatrix4x4());
1657 node->addTextDocument(QPointF(d->xoff, d->yoff), d->document, d->color, QQuickText::Normal, QColor(),
1658 QColor(), d->selectionColor, d->selectedTextColor, selectionStart(),
1659 selectionEnd() - 1); // selectionEnd() returns first char after
1663 if (d->cursorComponent == 0 && !isReadOnly()) {
1664 QQuickTextNode *node = static_cast<QQuickTextNode *>(currentNode);
1666 QColor color = (!d->cursorVisible || !d->control->cursorOn())
1667 ? QColor(0, 0, 0, 0)
1670 if (node->cursorNode() == 0) {
1671 node->setCursor(cursorRectangle(), color);
1673 node->cursorNode()->setRect(cursorRectangle());
1674 node->cursorNode()->setColor(color);
1683 \qmlproperty bool QtQuick2::TextEdit::smooth
1685 This property holds whether the text is smoothly scaled or transformed.
1687 Smooth filtering gives better visual quality, but is slower. If
1688 the item is displayed at its natural size, this property has no visual or
1691 \note Generally scaling artifacts are only visible if the item is stationary on
1692 the screen. A common pattern when animating an item is to disable smooth
1693 filtering at the beginning of the animation and reenable it at the conclusion.
1697 \qmlproperty bool QtQuick2::TextEdit::canPaste
1699 Returns true if the TextEdit is writable and the content of the clipboard is
1700 suitable for pasting into the TextEdit.
1702 bool QQuickTextEdit::canPaste() const
1704 Q_D(const QQuickTextEdit);
1705 if (!d->canPasteValid) {
1706 const_cast<QQuickTextEditPrivate *>(d)->canPaste = d->control->canPaste();
1707 const_cast<QQuickTextEditPrivate *>(d)->canPasteValid = true;
1713 \qmlproperty bool QtQuick2::TextEdit::canUndo
1715 Returns true if the TextEdit is writable and there are previous operations
1719 bool QQuickTextEdit::canUndo() const
1721 Q_D(const QQuickTextEdit);
1722 return d->document->isUndoAvailable();
1726 \qmlproperty bool QtQuick2::TextEdit::canRedo
1728 Returns true if the TextEdit is writable and there are \l {undo}{undone}
1729 operations that can be redone.
1732 bool QQuickTextEdit::canRedo() const
1734 Q_D(const QQuickTextEdit);
1735 return d->document->isRedoAvailable();
1739 \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1742 This property holds whether the TextEdit has partial text input from an
1745 While it is composing an input method may rely on mouse or key events from
1746 the TextEdit to edit or commit the partial text. This property can be used
1747 to determine when to disable events handlers that may interfere with the
1748 correct operation of an input method.
1750 bool QQuickTextEdit::isInputMethodComposing() const
1752 Q_D(const QQuickTextEdit);
1753 return d->control->hasImState();
1756 void QQuickTextEditPrivate::init()
1758 Q_Q(QQuickTextEdit);
1760 q->setSmooth(smooth);
1761 q->setAcceptedMouseButtons(Qt::LeftButton);
1762 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1763 q->setFlag(QQuickItem::ItemHasContents);
1765 document = new QQuickTextDocumentWithImageResources(q);
1767 control = new QQuickTextControl(document, q);
1768 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1769 control->setAcceptRichText(false);
1770 control->setCursorIsFocusIndicator(true);
1772 qmlobject_connect(control, QQuickTextControl, SIGNAL(updateRequest()), q, QQuickTextEdit, SLOT(updateDocument()));
1773 qmlobject_connect(control, QQuickTextControl, SIGNAL(updateCursorRequest()), q, QQuickTextEdit, SLOT(updateCursor()));
1774 qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged()));
1775 qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SIGNAL(selectedTextChanged()));
1776 qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SLOT(updateSelectionMarkers()));
1777 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SLOT(updateSelectionMarkers()));
1778 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SIGNAL(cursorPositionChanged()));
1779 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate()));
1780 qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString)));
1781 #ifndef QT_NO_CLIPBOARD
1782 qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()), q, QQuickTextEdit, SLOT(q_canPasteChanged()));
1784 qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(undoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canUndoChanged()));
1785 qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(redoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canRedoChanged()));
1786 qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()), q, QQuickTextEdit, SLOT(updateSize()));
1788 document->setDefaultFont(font);
1789 document->setDocumentMargin(textMargin);
1790 document->setUndoRedoEnabled(false); // flush undo buffer.
1791 document->setUndoRedoEnabled(true);
1792 updateDefaultTextOption();
1795 void QQuickTextEdit::q_textChanged()
1797 Q_D(QQuickTextEdit);
1798 d->textCached = false;
1799 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1800 d->contentDirection = d->textDirection(it.text());
1801 if (d->contentDirection != Qt::LayoutDirectionAuto)
1804 d->determineHorizontalAlignment();
1805 d->updateDefaultTextOption();
1811 void QQuickTextEdit::moveCursorDelegate()
1813 Q_D(QQuickTextEdit);
1814 updateInputMethod();
1815 emit cursorRectangleChanged();
1818 QRectF cursorRect = cursorRectangle();
1819 d->cursorItem->setX(cursorRect.x());
1820 d->cursorItem->setY(cursorRect.y());
1823 void QQuickTextEdit::updateSelectionMarkers()
1825 Q_D(QQuickTextEdit);
1826 if (d->lastSelectionStart != d->control->textCursor().selectionStart()) {
1827 d->lastSelectionStart = d->control->textCursor().selectionStart();
1828 emit selectionStartChanged();
1830 if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) {
1831 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1832 emit selectionEndChanged();
1836 QRectF QQuickTextEdit::boundingRect() const
1838 Q_D(const QQuickTextEdit);
1840 QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign()),
1842 d->contentSize.width(),
1843 d->contentSize.height());
1845 int cursorWidth = 1;
1848 else if (!d->document->isEmpty())
1849 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1851 // Could include font max left/right bearings to either side of rectangle.
1852 r.setRight(r.right() + cursorWidth);
1857 QRectF QQuickTextEdit::clipRect() const
1859 Q_D(const QQuickTextEdit);
1860 QRectF r = QQuickImplicitSizeItem::clipRect();
1861 int cursorWidth = 1;
1863 cursorWidth = d->cursorItem->width();
1864 if (!d->document->isEmpty())
1865 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1867 // Could include font max left/right bearings to either side of rectangle.
1869 r.setRight(r.right() + cursorWidth);
1873 qreal QQuickTextEditPrivate::getImplicitWidth() const
1875 Q_Q(const QQuickTextEdit);
1876 if (!requireImplicitWidth) {
1877 // We don't calculate implicitWidth unless it is required.
1878 // We need to force a size update now to ensure implicitWidth is calculated
1879 const_cast<QQuickTextEditPrivate*>(this)->requireImplicitWidth = true;
1880 const_cast<QQuickTextEdit*>(q)->updateSize();
1882 return implicitWidth;
1885 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1886 // need to do all the calculations each time
1887 void QQuickTextEdit::updateSize()
1889 Q_D(QQuickTextEdit);
1890 if (isComponentComplete()) {
1891 qreal naturalWidth = d->implicitWidth;
1892 // ### assumes that if the width is set, the text will fill to edges
1893 // ### (unless wrap is false, then clipping will occur)
1895 if (!d->requireImplicitWidth) {
1896 emit implicitWidthChanged();
1897 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1898 if (d->requireImplicitWidth)
1901 if (d->requireImplicitWidth) {
1902 d->document->setTextWidth(-1);
1903 naturalWidth = d->document->idealWidth();
1905 const bool wasInLayout = d->inLayout;
1907 setImplicitWidth(naturalWidth);
1908 d->inLayout = wasInLayout;
1909 if (d->inLayout) // probably the result of a binding loop, but by letting it
1910 return; // get this far we'll get a warning to that effect.
1912 if (d->document->textWidth() != width())
1913 d->document->setTextWidth(width());
1915 d->document->setTextWidth(-1);
1918 //### need to confirm cost of always setting these
1919 qreal newWidth = d->document->idealWidth();
1920 if ((!widthValid() || d->wrapMode == NoWrap) && d->document->textWidth() != newWidth)
1921 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set or the idealWidth exceeds the textWidth (QTextDoc bug)
1922 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1924 if (!widthValid() && !d->requireImplicitWidth)
1927 QFontMetricsF fm(d->font);
1928 qreal newHeight = d->document->isEmpty() ? qCeil(fm.height()) : d->document->size().height();
1931 setImplicitSize(iWidth, newHeight);
1933 setImplicitHeight(newHeight);
1935 d->xoff = QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign());
1936 d->yoff = QQuickTextUtil::alignedY(d->document->size().height(), height(), d->vAlign);
1937 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1939 QSizeF size(newWidth, newHeight);
1940 if (d->contentSize != size) {
1941 d->contentSize = size;
1942 emit contentSizeChanged();
1950 void QQuickTextEdit::updateDocument()
1952 Q_D(QQuickTextEdit);
1953 d->documentDirty = true;
1955 if (isComponentComplete()) {
1956 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1961 void QQuickTextEdit::updateCursor()
1963 Q_D(QQuickTextEdit);
1964 if (isComponentComplete()) {
1965 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1970 void QQuickTextEdit::q_updateAlignment()
1972 Q_D(QQuickTextEdit);
1973 if (d->determineHorizontalAlignment()) {
1974 d->updateDefaultTextOption();
1975 d->xoff = QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign());
1976 moveCursorDelegate();
1980 void QQuickTextEdit::updateTotalLines()
1982 Q_D(QQuickTextEdit);
1986 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1987 QTextLayout *layout = it.layout();
1990 subLines += layout->lineCount()-1;
1993 int newTotalLines = d->document->lineCount() + subLines;
1994 if (d->lineCount != newTotalLines) {
1995 d->lineCount = newTotalLines;
1996 emit lineCountChanged();
2000 void QQuickTextEditPrivate::updateDefaultTextOption()
2002 Q_Q(QQuickTextEdit);
2003 QTextOption opt = document->defaultTextOption();
2004 int oldAlignment = opt.alignment();
2005 Qt::LayoutDirection oldTextDirection = opt.textDirection();
2007 QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
2008 if (contentDirection == Qt::RightToLeft) {
2009 if (horizontalAlignment == QQuickTextEdit::AlignLeft)
2010 horizontalAlignment = QQuickTextEdit::AlignRight;
2011 else if (horizontalAlignment == QQuickTextEdit::AlignRight)
2012 horizontalAlignment = QQuickTextEdit::AlignLeft;
2014 if (!hAlignImplicit)
2015 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
2017 opt.setAlignment(Qt::Alignment(vAlign));
2019 if (contentDirection == Qt::LayoutDirectionAuto) {
2020 opt.setTextDirection(qGuiApp->inputMethod()->inputDirection());
2022 opt.setTextDirection(contentDirection);
2025 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
2026 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
2028 bool oldUseDesignMetrics = opt.useDesignMetrics();
2029 opt.setUseDesignMetrics(renderType != QQuickTextEdit::NativeRendering);
2031 if (oldWrapMode != opt.wrapMode() || oldAlignment != opt.alignment()
2032 || oldTextDirection != opt.textDirection()
2033 || oldUseDesignMetrics != opt.useDesignMetrics()) {
2034 document->setDefaultTextOption(opt);
2038 void QQuickTextEdit::focusInEvent(QFocusEvent *event)
2040 Q_D(const QQuickTextEdit);
2041 if (d->focusOnPress && !isReadOnly())
2042 qGuiApp->inputMethod()->show();
2043 QQuickImplicitSizeItem::focusInEvent(event);
2046 void QQuickTextEdit::q_canPasteChanged()
2048 Q_D(QQuickTextEdit);
2049 bool old = d->canPaste;
2050 d->canPaste = d->control->canPaste();
2051 bool changed = old!=d->canPaste || !d->canPasteValid;
2052 d->canPasteValid = true;
2054 emit canPasteChanged();
2058 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2060 Returns the section of text that is between the \a start and \a end positions.
2062 The returned text does not include any rich text formatting.
2065 QString QQuickTextEdit::getText(int start, int end) const
2067 Q_D(const QQuickTextEdit);
2068 start = qBound(0, start, d->document->characterCount() - 1);
2069 end = qBound(0, end, d->document->characterCount() - 1);
2070 QTextCursor cursor(d->document);
2071 cursor.setPosition(start, QTextCursor::MoveAnchor);
2072 cursor.setPosition(end, QTextCursor::KeepAnchor);
2073 #ifndef QT_NO_TEXTHTMLPARSER
2075 ? cursor.selectedText()
2076 : cursor.selection().toPlainText();
2078 return cursor.selection().toPlainText();
2083 \qmlmethod string QtQuick2::TextEdit::getFormattedText(int start, int end)
2085 Returns the section of text that is between the \a start and \a end positions.
2087 The returned text will be formatted according the \l textFormat property.
2090 QString QQuickTextEdit::getFormattedText(int start, int end) const
2092 Q_D(const QQuickTextEdit);
2094 start = qBound(0, start, d->document->characterCount() - 1);
2095 end = qBound(0, end, d->document->characterCount() - 1);
2097 QTextCursor cursor(d->document);
2098 cursor.setPosition(start, QTextCursor::MoveAnchor);
2099 cursor.setPosition(end, QTextCursor::KeepAnchor);
2102 #ifndef QT_NO_TEXTHTMLPARSER
2103 return cursor.selection().toHtml();
2105 return cursor.selection().toPlainText();
2108 return cursor.selection().toPlainText();
2113 \qmlmethod void QtQuick2::TextEdit::insert(int position, string text)
2115 Inserts \a text into the TextEdit at position.
2117 void QQuickTextEdit::insert(int position, const QString &text)
2119 Q_D(QQuickTextEdit);
2120 if (position < 0 || position >= d->document->characterCount())
2122 QTextCursor cursor(d->document);
2123 cursor.setPosition(position);
2124 d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text));
2126 #ifndef QT_NO_TEXTHTMLPARSER
2127 cursor.insertHtml(text);
2129 cursor.insertText(text);
2132 cursor.insertText(text);
2134 d->control->updateCursorRectangle(false);
2138 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2140 Removes the section of text that is between the \a start and \a end positions from the TextEdit.
2143 void QQuickTextEdit::remove(int start, int end)
2145 Q_D(QQuickTextEdit);
2146 start = qBound(0, start, d->document->characterCount() - 1);
2147 end = qBound(0, end, d->document->characterCount() - 1);
2148 QTextCursor cursor(d->document);
2149 cursor.setPosition(start, QTextCursor::MoveAnchor);
2150 cursor.setPosition(end, QTextCursor::KeepAnchor);
2151 cursor.removeSelectedText();
2152 d->control->updateCursorRectangle(false);