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>
69 \instantiates QQuickTextEdit
70 \inqmlmodule QtQuick 2
71 \ingroup qtquick-visual
72 \ingroup qtquick-input
74 \brief Displays multiple lines of editable formatted text
76 The TextEdit item displays a block of editable, formatted text.
78 It can display both plain and rich text. For example:
83 text: "<b>Hello</b> <i>World!</i>"
84 font.family: "Helvetica"
91 \image declarative-textedit.gif
93 Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
95 Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
96 to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
98 \snippet qml/texteditor.qml 0
100 A particular look-and-feel might use smooth scrolling (eg. using SmoothedAnimation), might have a visible
101 scrollbar, or a scrollbar that fades in to show location, etc.
103 Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
104 be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
105 from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
107 You can translate between cursor positions (characters from the start of the document) and pixel
108 points using positionAt() and positionToRectangle().
110 \sa Text, TextInput, {examples/quick/text/textselection}{Text Selection example}
114 \qmlsignal QtQuick2::TextEdit::onLinkActivated(string link)
116 This handler is called when the user clicks on a link embedded in the text.
117 The link must be in rich text or HTML format and the
118 \a link string provides access to the particular link.
120 QQuickTextEdit::QQuickTextEdit(QQuickItem *parent)
121 : QQuickImplicitSizeItem(*(new QQuickTextEditPrivate), parent)
127 QString QQuickTextEdit::text() const
129 Q_D(const QQuickTextEdit);
130 if (!d->textCached) {
131 QQuickTextEditPrivate *d = const_cast<QQuickTextEditPrivate *>(d_func());
132 #ifndef QT_NO_TEXTHTMLPARSER
134 d->text = d->control->toHtml();
137 d->text = d->control->toPlainText();
138 d->textCached = true;
144 \qmlproperty string QtQuick2::TextEdit::font.family
146 Sets the family name of the font.
148 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
149 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
150 If the family isn't available a family will be set using the font matching algorithm.
154 \qmlproperty bool QtQuick2::TextEdit::font.bold
156 Sets whether the font weight is bold.
160 \qmlproperty enumeration QtQuick2::TextEdit::font.weight
162 Sets the font's weight.
164 The weight can be one of:
167 \li Font.Normal - the default
174 TextEdit { text: "Hello"; font.weight: Font.DemiBold }
179 \qmlproperty bool QtQuick2::TextEdit::font.italic
181 Sets whether the font has an italic style.
185 \qmlproperty bool QtQuick2::TextEdit::font.underline
187 Sets whether the text is underlined.
191 \qmlproperty bool QtQuick2::TextEdit::font.strikeout
193 Sets whether the font has a strikeout style.
197 \qmlproperty real QtQuick2::TextEdit::font.pointSize
199 Sets the font size in points. The point size must be greater than zero.
203 \qmlproperty int QtQuick2::TextEdit::font.pixelSize
205 Sets the font size in pixels.
207 Using this function makes the font device dependent. Use
208 \l{TextEdit::font.pointSize} to set the size of the font in a
209 device independent manner.
213 \qmlproperty real QtQuick2::TextEdit::font.letterSpacing
215 Sets the letter spacing for the font.
217 Letter spacing changes the default spacing between individual letters in the font.
218 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
222 \qmlproperty real QtQuick2::TextEdit::font.wordSpacing
224 Sets the word spacing for the font.
226 Word spacing changes the default spacing between individual words.
227 A positive value increases the word spacing by a corresponding amount of pixels,
228 while a negative value decreases the inter-word spacing accordingly.
232 \qmlproperty enumeration QtQuick2::TextEdit::font.capitalization
234 Sets the capitalization for the text.
237 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
238 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
239 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
240 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
241 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
245 TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
250 \qmlproperty string QtQuick2::TextEdit::text
252 The text to display. If the text format is AutoText the text edit will
253 automatically determine whether the text should be treated as
254 rich text. This determination is made using Qt::mightBeRichText().
256 void QQuickTextEdit::setText(const QString &text)
259 if (QQuickTextEdit::text() == text)
262 d->document->clearResources();
263 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
264 if (!isComponentComplete()) {
266 } else if (d->richText) {
267 #ifndef QT_NO_TEXTHTMLPARSER
268 d->control->setHtml(text);
270 d->control->setPlainText(text);
273 d->control->setPlainText(text);
278 \qmlproperty enumeration QtQuick2::TextEdit::textFormat
280 The way the text property should be displayed.
283 \li TextEdit.AutoText
284 \li TextEdit.PlainText
285 \li TextEdit.RichText
288 The default is TextEdit.PlainText. If the text format is TextEdit.AutoText the text edit
289 will automatically determine whether the text should be treated as
290 rich text. This determination is made using Qt::mightBeRichText().
299 text: "<b>Hello</b> <i>World!</i>"
303 textFormat: TextEdit.RichText
304 text: "<b>Hello</b> <i>World!</i>"
308 textFormat: TextEdit.PlainText
309 text: "<b>Hello</b> <i>World!</i>"
313 \li \image declarative-textformat.png
316 QQuickTextEdit::TextFormat QQuickTextEdit::textFormat() const
318 Q_D(const QQuickTextEdit);
322 void QQuickTextEdit::setTextFormat(TextFormat format)
325 if (format == d->format)
328 bool wasRich = d->richText;
329 d->richText = format == RichText || (format == AutoText && (wasRich || Qt::mightBeRichText(text())));
331 #ifndef QT_NO_TEXTHTMLPARSER
332 if (isComponentComplete()) {
333 if (wasRich && !d->richText) {
334 d->control->setPlainText(!d->textCached ? d->control->toHtml() : d->text);
336 } else if (!wasRich && d->richText) {
337 d->control->setHtml(!d->textCached ? d->control->toPlainText() : d->text);
344 d->control->setAcceptRichText(d->format != PlainText);
345 emit textFormatChanged(d->format);
349 \qmlproperty enumeration QtQuick2::TextEdit::renderType
351 Override the default rendering type for this component.
353 Supported render types are:
355 \li Text.QtRendering - the default
356 \li Text.NativeRendering
359 Select Text.NativeRendering if you prefer text to look native on the target platform and do
360 not require advanced features such as transformation of the text. Using such features in
361 combination with the NativeRendering render type will lend poor and sometimes pixelated
364 QQuickTextEdit::RenderType QQuickTextEdit::renderType() const
366 Q_D(const QQuickTextEdit);
367 return d->renderType;
370 void QQuickTextEdit::setRenderType(QQuickTextEdit::RenderType renderType)
373 if (d->renderType == renderType)
376 d->renderType = renderType;
377 emit renderTypeChanged();
378 d->updateDefaultTextOption();
380 if (isComponentComplete())
384 QFont QQuickTextEdit::font() const
386 Q_D(const QQuickTextEdit);
387 return d->sourceFont;
390 void QQuickTextEdit::setFont(const QFont &font)
393 if (d->sourceFont == font)
396 d->sourceFont = font;
397 QFont oldFont = d->font;
399 if (d->font.pointSizeF() != -1) {
401 qreal size = qRound(d->font.pointSizeF()*2.0);
402 d->font.setPointSizeF(size/2.0);
405 if (oldFont != d->font) {
406 d->document->setDefaultFont(d->font);
408 d->cursorItem->setHeight(QFontMetrics(d->font).height());
409 moveCursorDelegate();
413 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
415 emit fontChanged(d->sourceFont);
419 \qmlproperty color QtQuick2::TextEdit::color
424 // green text using hexadecimal notation
425 TextEdit { color: "#00FF00" }
429 // steelblue text using SVG color name
430 TextEdit { color: "steelblue" }
433 QColor QQuickTextEdit::color() const
435 Q_D(const QQuickTextEdit);
439 void QQuickTextEdit::setColor(const QColor &color)
442 if (d->color == color)
447 emit colorChanged(d->color);
451 \qmlproperty color QtQuick2::TextEdit::selectionColor
453 The text highlight color, used behind selections.
455 QColor QQuickTextEdit::selectionColor() const
457 Q_D(const QQuickTextEdit);
458 return d->selectionColor;
461 void QQuickTextEdit::setSelectionColor(const QColor &color)
464 if (d->selectionColor == color)
467 d->selectionColor = color;
469 emit selectionColorChanged(d->selectionColor);
473 \qmlproperty color QtQuick2::TextEdit::selectedTextColor
475 The selected text color, used in selections.
477 QColor QQuickTextEdit::selectedTextColor() const
479 Q_D(const QQuickTextEdit);
480 return d->selectedTextColor;
483 void QQuickTextEdit::setSelectedTextColor(const QColor &color)
486 if (d->selectedTextColor == color)
489 d->selectedTextColor = color;
491 emit selectedTextColorChanged(d->selectedTextColor);
495 \qmlproperty enumeration QtQuick2::TextEdit::horizontalAlignment
496 \qmlproperty enumeration QtQuick2::TextEdit::verticalAlignment
497 \qmlproperty enumeration QtQuick2::TextEdit::effectiveHorizontalAlignment
499 Sets the horizontal and vertical alignment of the text within the TextEdit item's
500 width and height. By default, the text alignment follows the natural alignment
501 of the text, for example text that is read from left to right will be aligned to
504 Valid values for \c horizontalAlignment are:
506 \li TextEdit.AlignLeft (default)
507 \li TextEdit.AlignRight
508 \li TextEdit.AlignHCenter
509 \li TextEdit.AlignJustify
512 Valid values for \c verticalAlignment are:
514 \li TextEdit.AlignTop (default)
515 \li TextEdit.AlignBottom
516 \li TextEdit.AlignVCenter
519 When using the attached property LayoutMirroring::enabled to mirror application
520 layouts, the horizontal alignment of text will also be mirrored. However, the property
521 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
522 of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
524 QQuickTextEdit::HAlignment QQuickTextEdit::hAlign() const
526 Q_D(const QQuickTextEdit);
530 void QQuickTextEdit::setHAlign(HAlignment align)
533 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
534 d->hAlignImplicit = false;
535 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
536 d->updateDefaultTextOption();
541 void QQuickTextEdit::resetHAlign()
544 d->hAlignImplicit = true;
545 if (d->determineHorizontalAlignment() && isComponentComplete()) {
546 d->updateDefaultTextOption();
551 QQuickTextEdit::HAlignment QQuickTextEdit::effectiveHAlign() const
553 Q_D(const QQuickTextEdit);
554 QQuickTextEdit::HAlignment effectiveAlignment = d->hAlign;
555 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
557 case QQuickTextEdit::AlignLeft:
558 effectiveAlignment = QQuickTextEdit::AlignRight;
560 case QQuickTextEdit::AlignRight:
561 effectiveAlignment = QQuickTextEdit::AlignLeft;
567 return effectiveAlignment;
570 bool QQuickTextEditPrivate::setHAlign(QQuickTextEdit::HAlignment alignment, bool forceAlign)
573 if (hAlign != alignment || forceAlign) {
574 QQuickTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
576 emit q->horizontalAlignmentChanged(alignment);
577 if (oldEffectiveHAlign != q->effectiveHAlign())
578 emit q->effectiveHorizontalAlignmentChanged();
585 Qt::LayoutDirection QQuickTextEditPrivate::textDirection(const QString &text) const
587 const QChar *character = text.constData();
588 while (!character->isNull()) {
589 switch (character->direction()) {
591 return Qt::LeftToRight;
595 return Qt::RightToLeft;
601 return Qt::LayoutDirectionAuto;
604 bool QQuickTextEditPrivate::determineHorizontalAlignment()
607 if (hAlignImplicit && q->isComponentComplete()) {
608 Qt::LayoutDirection direction = contentDirection;
609 if (direction == Qt::LayoutDirectionAuto) {
610 const QString preeditText = control->textCursor().block().layout()->preeditAreaText();
611 direction = textDirection(preeditText);
613 if (direction == Qt::LayoutDirectionAuto)
614 direction = qGuiApp->inputMethod()->inputDirection();
616 return setHAlign(direction == Qt::RightToLeft ? QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft);
621 void QQuickTextEditPrivate::mirrorChange()
624 if (q->isComponentComplete()) {
625 if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) {
626 updateDefaultTextOption();
628 emit q->effectiveHorizontalAlignmentChanged();
633 QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const
635 Q_D(const QQuickTextEdit);
639 void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment)
642 if (alignment == d->vAlign)
644 d->vAlign = alignment;
645 d->updateDefaultTextOption();
647 moveCursorDelegate();
648 emit verticalAlignmentChanged(d->vAlign);
651 \qmlproperty enumeration QtQuick2::TextEdit::wrapMode
653 Set this property to wrap the text to the TextEdit item's width.
654 The text will only wrap if an explicit width has been set.
657 \li TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
658 \li TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
659 \li TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
660 \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.
663 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
665 QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode() const
667 Q_D(const QQuickTextEdit);
671 void QQuickTextEdit::setWrapMode(WrapMode mode)
674 if (mode == d->wrapMode)
677 d->updateDefaultTextOption();
679 emit wrapModeChanged();
683 \qmlproperty int QtQuick2::TextEdit::lineCount
685 Returns the total number of lines in the textEdit item.
687 int QQuickTextEdit::lineCount() const
689 Q_D(const QQuickTextEdit);
694 \qmlproperty int QtQuick2::TextEdit::length
696 Returns the total number of plain text characters in the TextEdit item.
698 As this number doesn't include any formatting markup it may not be the same as the
699 length of the string returned by the \l text property.
701 This property can be faster than querying the length the \l text property as it doesn't
702 require any copying or conversion of the TextEdit's internal string data.
705 int QQuickTextEdit::length() const
707 Q_D(const QQuickTextEdit);
708 // QTextDocument::characterCount() includes the terminating null character.
709 return qMax(0, d->document->characterCount() - 1);
713 \qmlproperty real QtQuick2::TextEdit::contentWidth
715 Returns the width of the text, including the width past the width
716 which is covered due to insufficient wrapping if \l wrapMode is set.
718 qreal QQuickTextEdit::contentWidth() const
720 Q_D(const QQuickTextEdit);
721 return d->contentSize.width();
725 \qmlproperty real QtQuick2::TextEdit::contentHeight
727 Returns the height of the text, including the height past the height
728 that is covered if the text does not fit within the set height.
730 qreal QQuickTextEdit::contentHeight() const
732 Q_D(const QQuickTextEdit);
733 return d->contentSize.height();
737 \qmlproperty url QtQuick2::TextEdit::baseUrl
739 This property specifies a base URL which is used to resolve relative URLs
742 The default value is the url of the QML file instantiating the TextEdit item.
745 QUrl QQuickTextEdit::baseUrl() const
747 Q_D(const QQuickTextEdit);
748 if (d->baseUrl.isEmpty()) {
749 if (QQmlContext *context = qmlContext(this))
750 const_cast<QQuickTextEditPrivate *>(d)->baseUrl = context->baseUrl();
755 void QQuickTextEdit::setBaseUrl(const QUrl &url)
758 if (baseUrl() != url) {
761 d->document->setBaseUrl(url, d->richText);
762 emit baseUrlChanged();
766 void QQuickTextEdit::resetBaseUrl()
768 if (QQmlContext *context = qmlContext(this))
769 setBaseUrl(context->baseUrl());
775 \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position)
777 Returns the rectangle at the given \a position in the text. The x, y,
778 and height properties correspond to the cursor that would describe
781 QRectF QQuickTextEdit::positionToRectangle(int pos) const
783 Q_D(const QQuickTextEdit);
784 QTextCursor c(d->document);
786 return d->control->cursorRect(c).translated(d->xoff, d->yoff);
791 \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y)
793 Returns the text position closest to pixel position (\a x, \a y).
795 Position 0 is before the first character, position 1 is after the first character
796 but before the second, and so on until position \l {text}.length, which is after all characters.
798 int QQuickTextEdit::positionAt(qreal x, qreal y) const
800 Q_D(const QQuickTextEdit);
804 int r = d->document->documentLayout()->hitTest(QPointF(x, y), Qt::FuzzyHit);
805 QTextCursor cursor = d->control->textCursor();
806 if (r > cursor.position()) {
807 // The cursor position includes positions within the preedit text, but only positions in the
808 // same text block are offset so it is possible to get a position that is either part of the
809 // preedit or the next text block.
810 QTextLayout *layout = cursor.block().layout();
811 const int preeditLength = layout
812 ? layout->preeditAreaText().length()
814 if (preeditLength > 0
815 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x, y)) {
816 r = r > cursor.position() + preeditLength
825 \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
827 Moves the cursor to \a position and updates the selection according to the optional \a mode
828 parameter. (To only move the cursor, set the \l cursorPosition property.)
830 When this method is called it additionally sets either the
831 selectionStart or the selectionEnd (whichever was at the previous cursor position)
832 to the specified position. This allows you to easily extend and contract the selected
835 The selection mode specifies whether the selection is updated on a per character or a per word
836 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
839 \li TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
840 the previous cursor position) to the specified position.
841 \li TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
842 words between the specified position and the previous cursor position. Words partially in the
846 For example, take this sequence of calls:
850 moveCursorSelection(9, TextEdit.SelectCharacters)
851 moveCursorSelection(7, TextEdit.SelectCharacters)
854 This moves the cursor to position 5, extend the selection end from 5 to 9
855 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
856 selected (the 6th and 7th characters).
858 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
859 before or on position 5 and extend the selection end to a word boundary on or past position 9.
861 void QQuickTextEdit::moveCursorSelection(int pos)
863 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
865 QTextCursor cursor = d->control->textCursor();
866 if (cursor.position() == pos)
868 cursor.setPosition(pos, QTextCursor::KeepAnchor);
869 d->control->setTextCursor(cursor);
872 void QQuickTextEdit::moveCursorSelection(int pos, SelectionMode mode)
875 QTextCursor cursor = d->control->textCursor();
876 if (cursor.position() == pos)
878 if (mode == SelectCharacters) {
879 cursor.setPosition(pos, QTextCursor::KeepAnchor);
880 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
881 if (cursor.anchor() > cursor.position()) {
882 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
883 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
884 if (cursor.position() == cursor.anchor())
885 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
887 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
889 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
890 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
893 cursor.setPosition(pos, QTextCursor::KeepAnchor);
894 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
895 if (cursor.position() != pos)
896 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
897 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
898 if (cursor.anchor() < cursor.position()) {
899 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
900 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
902 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
903 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
904 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
905 if (cursor.position() != cursor.anchor()) {
906 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
907 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
911 cursor.setPosition(pos, QTextCursor::KeepAnchor);
912 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
913 if (cursor.position() != pos) {
914 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
915 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
918 d->control->setTextCursor(cursor);
922 \qmlproperty bool QtQuick2::TextEdit::cursorVisible
923 If true the text edit shows a cursor.
925 This property is set and unset when the text edit gets active focus, but it can also
926 be set directly (useful, for example, if a KeyProxy might forward keys to it).
928 bool QQuickTextEdit::isCursorVisible() const
930 Q_D(const QQuickTextEdit);
931 return d->cursorVisible;
934 void QQuickTextEdit::setCursorVisible(bool on)
937 if (d->cursorVisible == on)
939 d->cursorVisible = on;
940 if (on && isComponentComplete())
941 QQuickTextUtil::createCursor(d);
942 if (!on && !d->persistentSelection)
943 d->control->setCursorIsFocusIndicator(true);
944 d->control->setCursorVisible(on);
945 emit cursorVisibleChanged(d->cursorVisible);
949 \qmlproperty int QtQuick2::TextEdit::cursorPosition
950 The position of the cursor in the TextEdit.
952 int QQuickTextEdit::cursorPosition() const
954 Q_D(const QQuickTextEdit);
955 return d->control->textCursor().position();
958 void QQuickTextEdit::setCursorPosition(int pos)
961 if (pos < 0 || pos >= d->document->characterCount()) // characterCount includes the terminating null.
963 QTextCursor cursor = d->control->textCursor();
964 if (cursor.position() == pos && cursor.anchor() == pos)
966 cursor.setPosition(pos);
967 d->control->setTextCursor(cursor);
968 d->control->updateCursorRectangle(true);
972 \qmlproperty Component QtQuick2::TextEdit::cursorDelegate
973 The delegate for the cursor in the TextEdit.
975 If you set a cursorDelegate for a TextEdit, this delegate will be used for
976 drawing the cursor instead of the standard cursor. An instance of the
977 delegate will be created and managed by the text edit when a cursor is
978 needed, and the x and y properties of delegate instance will be set so as
979 to be one pixel before the top left of the current character.
981 Note that the root item of the delegate component must be a QQuickItem or
982 QQuickItem derived item.
984 QQmlComponent* QQuickTextEdit::cursorDelegate() const
986 Q_D(const QQuickTextEdit);
987 return d->cursorComponent;
990 void QQuickTextEdit::setCursorDelegate(QQmlComponent* c)
993 QQuickTextUtil::setCursorDelegate(d, c);
996 void QQuickTextEdit::createCursor()
999 d->cursorPending = true;
1000 QQuickTextUtil::createCursor(d);
1004 \qmlproperty int QtQuick2::TextEdit::selectionStart
1006 The cursor position before the first character in the current selection.
1008 This property is read-only. To change the selection, use select(start,end),
1009 selectAll(), or selectWord().
1011 \sa selectionEnd, cursorPosition, selectedText
1013 int QQuickTextEdit::selectionStart() const
1015 Q_D(const QQuickTextEdit);
1016 return d->control->textCursor().selectionStart();
1020 \qmlproperty int QtQuick2::TextEdit::selectionEnd
1022 The cursor position after the last character in the current selection.
1024 This property is read-only. To change the selection, use select(start,end),
1025 selectAll(), or selectWord().
1027 \sa selectionStart, cursorPosition, selectedText
1029 int QQuickTextEdit::selectionEnd() const
1031 Q_D(const QQuickTextEdit);
1032 return d->control->textCursor().selectionEnd();
1036 \qmlproperty string QtQuick2::TextEdit::selectedText
1038 This read-only property provides the text currently selected in the
1041 It is equivalent to the following snippet, but is faster and easier
1044 //myTextEdit is the id of the TextEdit
1045 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
1046 myTextEdit.selectionEnd);
1049 QString QQuickTextEdit::selectedText() const
1051 Q_D(const QQuickTextEdit);
1052 #ifndef QT_NO_TEXTHTMLPARSER
1054 ? d->control->textCursor().selectedText()
1055 : d->control->textCursor().selection().toPlainText();
1057 return d->control->textCursor().selection().toPlainText();
1062 \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress
1064 Whether the TextEdit should gain active focus on a mouse press. By default this is
1067 bool QQuickTextEdit::focusOnPress() const
1069 Q_D(const QQuickTextEdit);
1070 return d->focusOnPress;
1073 void QQuickTextEdit::setFocusOnPress(bool on)
1075 Q_D(QQuickTextEdit);
1076 if (d->focusOnPress == on)
1078 d->focusOnPress = on;
1079 emit activeFocusOnPressChanged(d->focusOnPress);
1083 \qmlproperty bool QtQuick2::TextEdit::persistentSelection
1085 Whether the TextEdit should keep the selection visible when it loses active focus to another
1086 item in the scene. By default this is set to true;
1088 bool QQuickTextEdit::persistentSelection() const
1090 Q_D(const QQuickTextEdit);
1091 return d->persistentSelection;
1094 void QQuickTextEdit::setPersistentSelection(bool on)
1096 Q_D(QQuickTextEdit);
1097 if (d->persistentSelection == on)
1099 d->persistentSelection = on;
1100 emit persistentSelectionChanged(d->persistentSelection);
1104 \qmlproperty real QtQuick2::TextEdit::textMargin
1106 The margin, in pixels, around the text in the TextEdit.
1108 qreal QQuickTextEdit::textMargin() const
1110 Q_D(const QQuickTextEdit);
1111 return d->textMargin;
1114 void QQuickTextEdit::setTextMargin(qreal margin)
1116 Q_D(QQuickTextEdit);
1117 if (d->textMargin == margin)
1119 d->textMargin = margin;
1120 d->document->setDocumentMargin(d->textMargin);
1121 emit textMarginChanged(d->textMargin);
1125 \qmlproperty enumeration QtQuick2::TextEdit::inputMethodHints
1127 Provides hints to the input method about the expected content of the text edit and how it
1130 The value is a bit-wise combination of flags or Qt.ImhNone if no hints are set.
1132 Flags that alter behaviour are:
1135 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1136 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1137 in any persistent storage like predictive user dictionary.
1138 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1139 when a sentence ends.
1140 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1141 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1142 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1143 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1145 \li Qt.ImhDate - The text editor functions as a date field.
1146 \li Qt.ImhTime - The text editor functions as a time field.
1149 Flags that restrict input (exclusive flags) are:
1152 \li Qt.ImhDigitsOnly - Only digits are allowed.
1153 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1154 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1155 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1156 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1157 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1158 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1164 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1168 Qt::InputMethodHints QQuickTextEdit::inputMethodHints() const
1170 Q_D(const QQuickTextEdit);
1171 return d->inputMethodHints;
1174 void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints)
1176 Q_D(QQuickTextEdit);
1178 if (hints == d->inputMethodHints)
1181 d->inputMethodHints = hints;
1182 updateInputMethod(Qt::ImHints);
1183 emit inputMethodHintsChanged();
1186 void QQuickTextEdit::geometryChanged(const QRectF &newGeometry,
1187 const QRectF &oldGeometry)
1189 Q_D(QQuickTextEdit);
1190 if (newGeometry.width() != oldGeometry.width() && widthValid() && !d->inLayout) {
1192 moveCursorDelegate();
1194 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1199 Ensures any delayed caching or data loading the class
1200 needs to performed is complete.
1202 void QQuickTextEdit::componentComplete()
1204 Q_D(QQuickTextEdit);
1205 QQuickImplicitSizeItem::componentComplete();
1207 d->document->setBaseUrl(baseUrl(), d->richText);
1208 #ifndef QT_NO_TEXTHTML_PARSER
1210 d->control->setHtml(d->text);
1213 if (!d->text.isEmpty())
1214 d->control->setPlainText(d->text);
1217 d->determineHorizontalAlignment();
1218 d->updateDefaultTextOption();
1222 if (d->cursorComponent && isCursorVisible())
1223 QQuickTextUtil::createCursor(d);
1226 \qmlproperty bool QtQuick2::TextEdit::selectByMouse
1230 If true, the user can use the mouse to select text in some
1231 platform-specific way. Note that for some platforms this may
1232 not be an appropriate interaction (eg. may conflict with how
1233 the text needs to behave inside a Flickable.
1235 bool QQuickTextEdit::selectByMouse() const
1237 Q_D(const QQuickTextEdit);
1238 return d->selectByMouse;
1241 void QQuickTextEdit::setSelectByMouse(bool on)
1243 Q_D(QQuickTextEdit);
1244 if (d->selectByMouse != on) {
1245 d->selectByMouse = on;
1246 setKeepMouseGrab(on);
1248 d->control->setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1250 d->control->setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1251 emit selectByMouseChanged(on);
1256 \qmlproperty enumeration QtQuick2::TextEdit::mouseSelectionMode
1258 Specifies how text should be selected using a mouse.
1261 \li TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1262 \li TextEdit.SelectWords - The selection is updated with whole words.
1265 This property only applies when \l selectByMouse is true.
1267 QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode() const
1269 Q_D(const QQuickTextEdit);
1270 return d->mouseSelectionMode;
1273 void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode)
1275 Q_D(QQuickTextEdit);
1276 if (d->mouseSelectionMode != mode) {
1277 d->mouseSelectionMode = mode;
1278 d->control->setWordSelectionEnabled(mode == SelectWords);
1279 emit mouseSelectionModeChanged(mode);
1284 \qmlproperty bool QtQuick2::TextEdit::readOnly
1286 Whether the user can interact with the TextEdit item. If this
1287 property is set to true the text cannot be edited by user interaction.
1289 By default this property is false.
1291 void QQuickTextEdit::setReadOnly(bool r)
1293 Q_D(QQuickTextEdit);
1294 if (r == isReadOnly())
1297 setFlag(QQuickItem::ItemAcceptsInputMethod, !r);
1298 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1299 if (d->selectByMouse)
1300 flags = flags | Qt::TextSelectableByMouse;
1302 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1303 d->control->setTextInteractionFlags(flags);
1305 d->control->moveCursor(QTextCursor::End);
1307 updateInputMethod(Qt::ImEnabled);
1308 q_canPasteChanged();
1309 emit readOnlyChanged(r);
1312 bool QQuickTextEdit::isReadOnly() const
1314 Q_D(const QQuickTextEdit);
1315 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1319 \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle
1321 The rectangle where the standard text cursor is rendered
1322 within the text edit. Read-only.
1324 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
1325 automatically when it changes. The width of the delegate is unaffected by changes in the
1328 QRectF QQuickTextEdit::cursorRectangle() const
1330 Q_D(const QQuickTextEdit);
1331 return d->control->cursorRect().translated(d->xoff, d->yoff);
1334 bool QQuickTextEdit::event(QEvent *event)
1336 Q_D(QQuickTextEdit);
1337 if (event->type() == QEvent::ShortcutOverride) {
1338 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1339 return event->isAccepted();
1341 return QQuickImplicitSizeItem::event(event);
1346 Handles the given key \a event.
1348 void QQuickTextEdit::keyPressEvent(QKeyEvent *event)
1350 Q_D(QQuickTextEdit);
1351 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1352 if (!event->isAccepted())
1353 QQuickImplicitSizeItem::keyPressEvent(event);
1358 Handles the given key \a event.
1360 void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event)
1362 Q_D(QQuickTextEdit);
1363 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1364 if (!event->isAccepted())
1365 QQuickImplicitSizeItem::keyReleaseEvent(event);
1369 \qmlmethod void QtQuick2::TextEdit::deselect()
1371 Removes active text selection.
1373 void QQuickTextEdit::deselect()
1375 Q_D(QQuickTextEdit);
1376 QTextCursor c = d->control->textCursor();
1378 d->control->setTextCursor(c);
1382 \qmlmethod void QtQuick2::TextEdit::selectAll()
1384 Causes all text to be selected.
1386 void QQuickTextEdit::selectAll()
1388 Q_D(QQuickTextEdit);
1389 d->control->selectAll();
1393 \qmlmethod void QtQuick2::TextEdit::selectWord()
1395 Causes the word closest to the current cursor position to be selected.
1397 void QQuickTextEdit::selectWord()
1399 Q_D(QQuickTextEdit);
1400 QTextCursor c = d->control->textCursor();
1401 c.select(QTextCursor::WordUnderCursor);
1402 d->control->setTextCursor(c);
1406 \qmlmethod void QtQuick2::TextEdit::select(int start, int end)
1408 Causes the text from \a start to \a end to be selected.
1410 If either start or end is out of range, the selection is not changed.
1412 After calling this, selectionStart will become the lesser
1413 and selectionEnd will become the greater (regardless of the order passed
1416 \sa selectionStart, selectionEnd
1418 void QQuickTextEdit::select(int start, int end)
1420 Q_D(QQuickTextEdit);
1421 if (start < 0 || end < 0 || start >= d->document->characterCount() || end >= d->document->characterCount())
1423 QTextCursor cursor = d->control->textCursor();
1424 cursor.beginEditBlock();
1425 cursor.setPosition(start, QTextCursor::MoveAnchor);
1426 cursor.setPosition(end, QTextCursor::KeepAnchor);
1427 cursor.endEditBlock();
1428 d->control->setTextCursor(cursor);
1431 updateSelectionMarkers();
1435 \qmlmethod void QtQuick2::TextEdit::isRightToLeft(int start, int end)
1437 Returns true if the natural reading direction of the editor text
1438 found between positions \a start and \a end is right to left.
1440 bool QQuickTextEdit::isRightToLeft(int start, int end)
1443 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1446 return getText(start, end).isRightToLeft();
1450 #ifndef QT_NO_CLIPBOARD
1452 \qmlmethod QtQuick2::TextEdit::cut()
1454 Moves the currently selected text to the system clipboard.
1456 void QQuickTextEdit::cut()
1458 Q_D(QQuickTextEdit);
1463 \qmlmethod QtQuick2::TextEdit::copy()
1465 Copies the currently selected text to the system clipboard.
1467 void QQuickTextEdit::copy()
1469 Q_D(QQuickTextEdit);
1474 \qmlmethod QtQuick2::TextEdit::paste()
1476 Replaces the currently selected text by the contents of the system clipboard.
1478 void QQuickTextEdit::paste()
1480 Q_D(QQuickTextEdit);
1481 d->control->paste();
1483 #endif // QT_NO_CLIPBOARD
1487 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1488 current selection, and updates the selection start to the current cursor
1492 void QQuickTextEdit::undo()
1494 Q_D(QQuickTextEdit);
1499 Redoes the last operation if redo is \l {canRedo}{available}.
1502 void QQuickTextEdit::redo()
1504 Q_D(QQuickTextEdit);
1510 Handles the given mouse \a event.
1512 void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
1514 Q_D(QQuickTextEdit);
1515 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1516 if (d->focusOnPress){
1517 bool hadActiveFocus = hasActiveFocus();
1519 // re-open input panel on press if already focused
1520 if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
1521 qGuiApp->inputMethod()->show();
1523 if (!event->isAccepted())
1524 QQuickImplicitSizeItem::mousePressEvent(event);
1529 Handles the given mouse \a event.
1531 void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
1533 Q_D(QQuickTextEdit);
1534 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1536 if (!event->isAccepted())
1537 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1542 Handles the given mouse \a event.
1544 void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
1546 Q_D(QQuickTextEdit);
1547 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1548 if (!event->isAccepted())
1549 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1554 Handles the given mouse \a event.
1556 void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
1558 Q_D(QQuickTextEdit);
1559 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1560 if (!event->isAccepted())
1561 QQuickImplicitSizeItem::mouseMoveEvent(event);
1566 Handles the given input method \a event.
1568 void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
1570 Q_D(QQuickTextEdit);
1571 const bool wasComposing = isInputMethodComposing();
1572 d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1573 setCursorVisible(d->control->cursorVisible());
1574 if (wasComposing != isInputMethodComposing())
1575 emit inputMethodComposingChanged();
1578 void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1580 Q_D(QQuickTextEdit);
1581 if (change == ItemActiveFocusHasChanged) {
1582 setCursorVisible(value.boolValue);
1583 QFocusEvent focusEvent(value.boolValue ? QEvent::FocusIn : QEvent::FocusOut);
1584 d->control->processEvent(&focusEvent, QPointF(-d->xoff, -d->yoff));
1585 if (value.boolValue) {
1586 q_updateAlignment();
1587 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1588 this, SLOT(q_updateAlignment()));
1590 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1591 this, SLOT(q_updateAlignment()));
1594 QQuickItem::itemChange(change, value);
1599 Returns the value of the given \a property.
1601 QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1603 Q_D(const QQuickTextEdit);
1608 v = (bool)(flags() & ItemAcceptsInputMethod);
1611 v = (int)inputMethodHints();
1614 v = d->control->inputMethodQuery(property);
1621 void QQuickTextEdit::triggerPreprocess()
1623 Q_D(QQuickTextEdit);
1624 if (d->updateType == QQuickTextEditPrivate::UpdateNone)
1625 d->updateType = QQuickTextEditPrivate::UpdateOnlyPreprocess;
1629 QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1631 Q_UNUSED(updatePaintNodeData);
1632 Q_D(QQuickTextEdit);
1634 if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode && oldNode != 0) {
1635 // Update done in preprocess() in the nodes
1636 d->updateType = QQuickTextEditPrivate::UpdateNone;
1640 d->updateType = QQuickTextEditPrivate::UpdateNone;
1642 QSGNode *currentNode = oldNode;
1643 if (oldNode == 0 || d->documentDirty) {
1644 d->documentDirty = false;
1646 QQuickTextNode *node = 0;
1648 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1651 node = static_cast<QQuickTextNode *>(oldNode);
1654 node->setUseNativeRenderer(d->renderType == NativeRendering);
1655 node->deleteContent();
1656 node->setMatrix(QMatrix4x4());
1658 node->addTextDocument(QPointF(d->xoff, d->yoff), d->document, d->color, QQuickText::Normal, QColor(),
1659 QColor(), d->selectionColor, d->selectedTextColor, selectionStart(),
1660 selectionEnd() - 1); // selectionEnd() returns first char after
1664 if (d->cursorComponent == 0 && !isReadOnly()) {
1665 QQuickTextNode *node = static_cast<QQuickTextNode *>(currentNode);
1667 QColor color = (!d->cursorVisible || !d->control->cursorOn())
1668 ? QColor(0, 0, 0, 0)
1671 if (node->cursorNode() == 0) {
1672 node->setCursor(cursorRectangle(), color);
1674 node->cursorNode()->setRect(cursorRectangle());
1675 node->cursorNode()->setColor(color);
1684 \qmlproperty bool QtQuick2::TextEdit::canPaste
1686 Returns true if the TextEdit is writable and the content of the clipboard is
1687 suitable for pasting into the TextEdit.
1689 bool QQuickTextEdit::canPaste() const
1691 Q_D(const QQuickTextEdit);
1692 if (!d->canPasteValid) {
1693 const_cast<QQuickTextEditPrivate *>(d)->canPaste = d->control->canPaste();
1694 const_cast<QQuickTextEditPrivate *>(d)->canPasteValid = true;
1700 \qmlproperty bool QtQuick2::TextEdit::canUndo
1702 Returns true if the TextEdit is writable and there are previous operations
1706 bool QQuickTextEdit::canUndo() const
1708 Q_D(const QQuickTextEdit);
1709 return d->document->isUndoAvailable();
1713 \qmlproperty bool QtQuick2::TextEdit::canRedo
1715 Returns true if the TextEdit is writable and there are \l {undo}{undone}
1716 operations that can be redone.
1719 bool QQuickTextEdit::canRedo() const
1721 Q_D(const QQuickTextEdit);
1722 return d->document->isRedoAvailable();
1726 \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1729 This property holds whether the TextEdit has partial text input from an
1732 While it is composing an input method may rely on mouse or key events from
1733 the TextEdit to edit or commit the partial text. This property can be used
1734 to determine when to disable events handlers that may interfere with the
1735 correct operation of an input method.
1737 bool QQuickTextEdit::isInputMethodComposing() const
1739 Q_D(const QQuickTextEdit);
1740 return d->control->hasImState();
1743 void QQuickTextEditPrivate::init()
1745 Q_Q(QQuickTextEdit);
1747 q->setAcceptedMouseButtons(Qt::LeftButton);
1748 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1749 q->setFlag(QQuickItem::ItemHasContents);
1751 document = new QQuickTextDocumentWithImageResources(q);
1753 control = new QQuickTextControl(document, q);
1754 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1755 control->setAcceptRichText(false);
1756 control->setCursorIsFocusIndicator(true);
1758 qmlobject_connect(control, QQuickTextControl, SIGNAL(updateRequest()), q, QQuickTextEdit, SLOT(updateDocument()));
1759 qmlobject_connect(control, QQuickTextControl, SIGNAL(updateCursorRequest()), q, QQuickTextEdit, SLOT(updateCursor()));
1760 qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged()));
1761 qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SIGNAL(selectedTextChanged()));
1762 qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SLOT(updateSelectionMarkers()));
1763 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SLOT(updateSelectionMarkers()));
1764 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SIGNAL(cursorPositionChanged()));
1765 qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate()));
1766 qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString)));
1767 #ifndef QT_NO_CLIPBOARD
1768 qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()), q, QQuickTextEdit, SLOT(q_canPasteChanged()));
1770 qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(undoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canUndoChanged()));
1771 qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(redoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canRedoChanged()));
1772 qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()), q, QQuickTextEdit, SLOT(updateSize()));
1774 document->setDefaultFont(font);
1775 document->setDocumentMargin(textMargin);
1776 document->setUndoRedoEnabled(false); // flush undo buffer.
1777 document->setUndoRedoEnabled(true);
1778 updateDefaultTextOption();
1781 void QQuickTextEdit::q_textChanged()
1783 Q_D(QQuickTextEdit);
1784 d->textCached = false;
1785 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1786 d->contentDirection = d->textDirection(it.text());
1787 if (d->contentDirection != Qt::LayoutDirectionAuto)
1790 d->determineHorizontalAlignment();
1791 d->updateDefaultTextOption();
1797 void QQuickTextEdit::moveCursorDelegate()
1799 Q_D(QQuickTextEdit);
1800 updateInputMethod();
1801 emit cursorRectangleChanged();
1804 QRectF cursorRect = cursorRectangle();
1805 d->cursorItem->setX(cursorRect.x());
1806 d->cursorItem->setY(cursorRect.y());
1809 void QQuickTextEdit::updateSelectionMarkers()
1811 Q_D(QQuickTextEdit);
1812 if (d->lastSelectionStart != d->control->textCursor().selectionStart()) {
1813 d->lastSelectionStart = d->control->textCursor().selectionStart();
1814 emit selectionStartChanged();
1816 if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) {
1817 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1818 emit selectionEndChanged();
1822 QRectF QQuickTextEdit::boundingRect() const
1824 Q_D(const QQuickTextEdit);
1826 QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign()),
1828 d->contentSize.width(),
1829 d->contentSize.height());
1831 int cursorWidth = 1;
1834 else if (!d->document->isEmpty())
1835 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1837 // Could include font max left/right bearings to either side of rectangle.
1838 r.setRight(r.right() + cursorWidth);
1843 QRectF QQuickTextEdit::clipRect() const
1845 Q_D(const QQuickTextEdit);
1846 QRectF r = QQuickImplicitSizeItem::clipRect();
1847 int cursorWidth = 1;
1849 cursorWidth = d->cursorItem->width();
1850 if (!d->document->isEmpty())
1851 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1853 // Could include font max left/right bearings to either side of rectangle.
1855 r.setRight(r.right() + cursorWidth);
1859 qreal QQuickTextEditPrivate::getImplicitWidth() const
1861 Q_Q(const QQuickTextEdit);
1862 if (!requireImplicitWidth) {
1863 // We don't calculate implicitWidth unless it is required.
1864 // We need to force a size update now to ensure implicitWidth is calculated
1865 const_cast<QQuickTextEditPrivate*>(this)->requireImplicitWidth = true;
1866 const_cast<QQuickTextEdit*>(q)->updateSize();
1868 return implicitWidth;
1871 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1872 // need to do all the calculations each time
1873 void QQuickTextEdit::updateSize()
1875 Q_D(QQuickTextEdit);
1876 if (isComponentComplete()) {
1877 qreal naturalWidth = d->implicitWidth;
1878 // ### assumes that if the width is set, the text will fill to edges
1879 // ### (unless wrap is false, then clipping will occur)
1881 if (!d->requireImplicitWidth) {
1882 emit implicitWidthChanged();
1883 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1884 if (d->requireImplicitWidth)
1887 if (d->requireImplicitWidth) {
1888 d->document->setTextWidth(-1);
1889 naturalWidth = d->document->idealWidth();
1891 const bool wasInLayout = d->inLayout;
1893 setImplicitWidth(naturalWidth);
1894 d->inLayout = wasInLayout;
1895 if (d->inLayout) // probably the result of a binding loop, but by letting it
1896 return; // get this far we'll get a warning to that effect.
1898 if (d->document->textWidth() != width())
1899 d->document->setTextWidth(width());
1901 d->document->setTextWidth(-1);
1904 //### need to confirm cost of always setting these
1905 qreal newWidth = d->document->idealWidth();
1906 if ((!widthValid() || d->wrapMode == NoWrap) && d->document->textWidth() != newWidth)
1907 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set or the idealWidth exceeds the textWidth (QTextDoc bug)
1908 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1910 if (!widthValid() && !d->requireImplicitWidth)
1913 QFontMetricsF fm(d->font);
1914 qreal newHeight = d->document->isEmpty() ? qCeil(fm.height()) : d->document->size().height();
1917 setImplicitSize(iWidth, newHeight);
1919 setImplicitHeight(newHeight);
1921 d->xoff = QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign());
1922 d->yoff = QQuickTextUtil::alignedY(d->document->size().height(), height(), d->vAlign);
1923 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1925 QSizeF size(newWidth, newHeight);
1926 if (d->contentSize != size) {
1927 d->contentSize = size;
1928 emit contentSizeChanged();
1936 void QQuickTextEdit::updateDocument()
1938 Q_D(QQuickTextEdit);
1939 d->documentDirty = true;
1941 if (isComponentComplete()) {
1942 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1947 void QQuickTextEdit::updateCursor()
1949 Q_D(QQuickTextEdit);
1950 if (isComponentComplete()) {
1951 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1956 void QQuickTextEdit::q_updateAlignment()
1958 Q_D(QQuickTextEdit);
1959 if (d->determineHorizontalAlignment()) {
1960 d->updateDefaultTextOption();
1961 d->xoff = QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign());
1962 moveCursorDelegate();
1966 void QQuickTextEdit::updateTotalLines()
1968 Q_D(QQuickTextEdit);
1972 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1973 QTextLayout *layout = it.layout();
1976 subLines += layout->lineCount()-1;
1979 int newTotalLines = d->document->lineCount() + subLines;
1980 if (d->lineCount != newTotalLines) {
1981 d->lineCount = newTotalLines;
1982 emit lineCountChanged();
1986 void QQuickTextEditPrivate::updateDefaultTextOption()
1988 Q_Q(QQuickTextEdit);
1989 QTextOption opt = document->defaultTextOption();
1990 int oldAlignment = opt.alignment();
1991 Qt::LayoutDirection oldTextDirection = opt.textDirection();
1993 QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
1994 if (contentDirection == Qt::RightToLeft) {
1995 if (horizontalAlignment == QQuickTextEdit::AlignLeft)
1996 horizontalAlignment = QQuickTextEdit::AlignRight;
1997 else if (horizontalAlignment == QQuickTextEdit::AlignRight)
1998 horizontalAlignment = QQuickTextEdit::AlignLeft;
2000 if (!hAlignImplicit)
2001 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
2003 opt.setAlignment(Qt::Alignment(vAlign));
2005 if (contentDirection == Qt::LayoutDirectionAuto) {
2006 opt.setTextDirection(qGuiApp->inputMethod()->inputDirection());
2008 opt.setTextDirection(contentDirection);
2011 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
2012 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
2014 bool oldUseDesignMetrics = opt.useDesignMetrics();
2015 opt.setUseDesignMetrics(renderType != QQuickTextEdit::NativeRendering);
2017 if (oldWrapMode != opt.wrapMode() || oldAlignment != opt.alignment()
2018 || oldTextDirection != opt.textDirection()
2019 || oldUseDesignMetrics != opt.useDesignMetrics()) {
2020 document->setDefaultTextOption(opt);
2024 void QQuickTextEdit::focusInEvent(QFocusEvent *event)
2026 Q_D(const QQuickTextEdit);
2027 if (d->focusOnPress && !isReadOnly())
2028 qGuiApp->inputMethod()->show();
2029 QQuickImplicitSizeItem::focusInEvent(event);
2032 void QQuickTextEdit::q_canPasteChanged()
2034 Q_D(QQuickTextEdit);
2035 bool old = d->canPaste;
2036 d->canPaste = d->control->canPaste();
2037 bool changed = old!=d->canPaste || !d->canPasteValid;
2038 d->canPasteValid = true;
2040 emit canPasteChanged();
2044 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2046 Returns the section of text that is between the \a start and \a end positions.
2048 The returned text does not include any rich text formatting.
2051 QString QQuickTextEdit::getText(int start, int end) const
2053 Q_D(const QQuickTextEdit);
2054 start = qBound(0, start, d->document->characterCount() - 1);
2055 end = qBound(0, end, d->document->characterCount() - 1);
2056 QTextCursor cursor(d->document);
2057 cursor.setPosition(start, QTextCursor::MoveAnchor);
2058 cursor.setPosition(end, QTextCursor::KeepAnchor);
2059 #ifndef QT_NO_TEXTHTMLPARSER
2061 ? cursor.selectedText()
2062 : cursor.selection().toPlainText();
2064 return cursor.selection().toPlainText();
2069 \qmlmethod string QtQuick2::TextEdit::getFormattedText(int start, int end)
2071 Returns the section of text that is between the \a start and \a end positions.
2073 The returned text will be formatted according the \l textFormat property.
2076 QString QQuickTextEdit::getFormattedText(int start, int end) const
2078 Q_D(const QQuickTextEdit);
2080 start = qBound(0, start, d->document->characterCount() - 1);
2081 end = qBound(0, end, d->document->characterCount() - 1);
2083 QTextCursor cursor(d->document);
2084 cursor.setPosition(start, QTextCursor::MoveAnchor);
2085 cursor.setPosition(end, QTextCursor::KeepAnchor);
2088 #ifndef QT_NO_TEXTHTMLPARSER
2089 return cursor.selection().toHtml();
2091 return cursor.selection().toPlainText();
2094 return cursor.selection().toPlainText();
2099 \qmlmethod void QtQuick2::TextEdit::insert(int position, string text)
2101 Inserts \a text into the TextEdit at position.
2103 void QQuickTextEdit::insert(int position, const QString &text)
2105 Q_D(QQuickTextEdit);
2106 if (position < 0 || position >= d->document->characterCount())
2108 QTextCursor cursor(d->document);
2109 cursor.setPosition(position);
2110 d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text));
2112 #ifndef QT_NO_TEXTHTMLPARSER
2113 cursor.insertHtml(text);
2115 cursor.insertText(text);
2118 cursor.insertText(text);
2120 d->control->updateCursorRectangle(false);
2124 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2126 Removes the section of text that is between the \a start and \a end positions from the TextEdit.
2129 void QQuickTextEdit::remove(int start, int end)
2131 Q_D(QQuickTextEdit);
2132 start = qBound(0, start, d->document->characterCount() - 1);
2133 end = qBound(0, end, d->document->characterCount() - 1);
2134 QTextCursor cursor(d->document);
2135 cursor.setPosition(start, QTextCursor::MoveAnchor);
2136 cursor.setPosition(end, QTextCursor::KeepAnchor);
2137 cursor.removeSelectedText();
2138 d->control->updateCursorRectangle(false);