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 "qquickcanvas.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 qml-basic-visual-elements
71 \brief The TextEdit item displays multiple lines of editable formatted text.
74 The TextEdit item displays a block of editable, formatted text.
76 It can display both plain and rich text. For example:
81 text: "<b>Hello</b> <i>World!</i>"
82 font.family: "Helvetica"
89 \image declarative-textedit.gif
91 Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
93 Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
94 to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
96 \snippet snippets/declarative/texteditor.qml 0
98 A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible
99 scrollbar, or a scrollbar that fades in to show location, etc.
101 Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
102 be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
103 from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
105 You can translate between cursor positions (characters from the start of the document) and pixel
106 points using positionAt() and positionToRectangle().
108 \sa Text, TextInput, {declarative/text/textselection}{Text Selection example}
112 \qmlsignal QtQuick2::TextEdit::onLinkActivated(string link)
114 This handler is called when the user clicks on a link embedded in the text.
115 The link must be in rich text or HTML format and the
116 \a link string provides access to the particular link.
118 QQuickTextEdit::QQuickTextEdit(QQuickItem *parent)
119 : QQuickImplicitSizeItem(*(new QQuickTextEditPrivate), parent)
125 QString QQuickTextEdit::text() const
127 Q_D(const QQuickTextEdit);
128 if (!d->textCached) {
129 QQuickTextEditPrivate *d = const_cast<QQuickTextEditPrivate *>(d_func());
130 #ifndef QT_NO_TEXTHTMLPARSER
132 d->text = d->control->toHtml();
135 d->text = d->control->toPlainText();
136 d->textCached = true;
142 \qmlproperty string QtQuick2::TextEdit::font.family
144 Sets the family name of the font.
146 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
147 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
148 If the family isn't available a family will be set using the font matching algorithm.
152 \qmlproperty bool QtQuick2::TextEdit::font.bold
154 Sets whether the font weight is bold.
158 \qmlproperty enumeration QtQuick2::TextEdit::font.weight
160 Sets the font's weight.
162 The weight can be one of:
165 \li Font.Normal - the default
172 TextEdit { text: "Hello"; font.weight: Font.DemiBold }
177 \qmlproperty bool QtQuick2::TextEdit::font.italic
179 Sets whether the font has an italic style.
183 \qmlproperty bool QtQuick2::TextEdit::font.underline
185 Sets whether the text is underlined.
189 \qmlproperty bool QtQuick2::TextEdit::font.strikeout
191 Sets whether the font has a strikeout style.
195 \qmlproperty real QtQuick2::TextEdit::font.pointSize
197 Sets the font size in points. The point size must be greater than zero.
201 \qmlproperty int QtQuick2::TextEdit::font.pixelSize
203 Sets the font size in pixels.
205 Using this function makes the font device dependent. Use
206 \l{TextEdit::font.pointSize} to set the size of the font in a
207 device independent manner.
211 \qmlproperty real QtQuick2::TextEdit::font.letterSpacing
213 Sets the letter spacing for the font.
215 Letter spacing changes the default spacing between individual letters in the font.
216 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
220 \qmlproperty real QtQuick2::TextEdit::font.wordSpacing
222 Sets the word spacing for the font.
224 Word spacing changes the default spacing between individual words.
225 A positive value increases the word spacing by a corresponding amount of pixels,
226 while a negative value decreases the inter-word spacing accordingly.
230 \qmlproperty enumeration QtQuick2::TextEdit::font.capitalization
232 Sets the capitalization for the text.
235 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
236 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
237 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
238 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
239 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
243 TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
248 \qmlproperty string QtQuick2::TextEdit::text
250 The text to display. If the text format is AutoText the text edit will
251 automatically determine whether the text should be treated as
252 rich text. This determination is made using Qt::mightBeRichText().
254 void QQuickTextEdit::setText(const QString &text)
257 if (QQuickTextEdit::text() == text)
260 d->document->clearResources();
261 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
263 #ifndef QT_NO_TEXTHTMLPARSER
264 d->control->setHtml(text);
266 d->control->setPlainText(text);
269 d->control->setPlainText(text);
274 \qmlproperty enumeration QtQuick2::TextEdit::textFormat
276 The way the text property should be displayed.
279 \li TextEdit.AutoText
280 \li TextEdit.PlainText
281 \li TextEdit.RichText
284 The default is TextEdit.PlainText. If the text format is TextEdit.AutoText the text edit
285 will automatically determine whether the text should be treated as
286 rich text. This determination is made using Qt::mightBeRichText().
295 text: "<b>Hello</b> <i>World!</i>"
299 textFormat: TextEdit.RichText
300 text: "<b>Hello</b> <i>World!</i>"
304 textFormat: TextEdit.PlainText
305 text: "<b>Hello</b> <i>World!</i>"
309 \li \image declarative-textformat.png
312 QQuickTextEdit::TextFormat QQuickTextEdit::textFormat() const
314 Q_D(const QQuickTextEdit);
318 void QQuickTextEdit::setTextFormat(TextFormat format)
321 if (format == d->format)
324 bool wasRich = d->richText;
325 d->richText = format == RichText || (format == AutoText && (wasRich || Qt::mightBeRichText(text())));
327 #ifndef QT_NO_TEXTHTMLPARSER
328 if (wasRich && !d->richText) {
329 d->control->setPlainText(!d->textCached ? d->control->toHtml() : d->text);
331 } else if (!wasRich && d->richText) {
332 d->control->setHtml(!d->textCached ? d->control->toPlainText() : d->text);
338 d->control->setAcceptRichText(d->format != PlainText);
339 emit textFormatChanged(d->format);
342 QFont QQuickTextEdit::font() const
344 Q_D(const QQuickTextEdit);
345 return d->sourceFont;
348 void QQuickTextEdit::setFont(const QFont &font)
351 if (d->sourceFont == font)
354 d->sourceFont = font;
355 QFont oldFont = d->font;
357 if (d->font.pointSizeF() != -1) {
359 qreal size = qRound(d->font.pointSizeF()*2.0);
360 d->font.setPointSizeF(size/2.0);
363 if (oldFont != d->font) {
364 d->document->setDefaultFont(d->font);
366 d->cursorItem->setHeight(QFontMetrics(d->font).height());
367 moveCursorDelegate();
371 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
373 emit fontChanged(d->sourceFont);
377 \qmlproperty color QtQuick2::TextEdit::color
382 // green text using hexadecimal notation
383 TextEdit { color: "#00FF00" }
387 // steelblue text using SVG color name
388 TextEdit { color: "steelblue" }
391 QColor QQuickTextEdit::color() const
393 Q_D(const QQuickTextEdit);
397 void QQuickTextEdit::setColor(const QColor &color)
400 if (d->color == color)
405 emit colorChanged(d->color);
409 \qmlproperty color QtQuick2::TextEdit::selectionColor
411 The text highlight color, used behind selections.
413 QColor QQuickTextEdit::selectionColor() const
415 Q_D(const QQuickTextEdit);
416 return d->selectionColor;
419 void QQuickTextEdit::setSelectionColor(const QColor &color)
422 if (d->selectionColor == color)
425 d->selectionColor = color;
427 emit selectionColorChanged(d->selectionColor);
431 \qmlproperty color QtQuick2::TextEdit::selectedTextColor
433 The selected text color, used in selections.
435 QColor QQuickTextEdit::selectedTextColor() const
437 Q_D(const QQuickTextEdit);
438 return d->selectedTextColor;
441 void QQuickTextEdit::setSelectedTextColor(const QColor &color)
444 if (d->selectedTextColor == color)
447 d->selectedTextColor = color;
449 emit selectedTextColorChanged(d->selectedTextColor);
453 \qmlproperty enumeration QtQuick2::TextEdit::horizontalAlignment
454 \qmlproperty enumeration QtQuick2::TextEdit::verticalAlignment
455 \qmlproperty enumeration QtQuick2::TextEdit::effectiveHorizontalAlignment
457 Sets the horizontal and vertical alignment of the text within the TextEdit item's
458 width and height. By default, the text alignment follows the natural alignment
459 of the text, for example text that is read from left to right will be aligned to
462 Valid values for \c horizontalAlignment are:
464 \li TextEdit.AlignLeft (default)
465 \li TextEdit.AlignRight
466 \li TextEdit.AlignHCenter
467 \li TextEdit.AlignJustify
470 Valid values for \c verticalAlignment are:
472 \li TextEdit.AlignTop (default)
473 \li TextEdit.AlignBottom
474 \li TextEdit.AlignVCenter
477 When using the attached property LayoutMirroring::enabled to mirror application
478 layouts, the horizontal alignment of text will also be mirrored. However, the property
479 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
480 of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
482 QQuickTextEdit::HAlignment QQuickTextEdit::hAlign() const
484 Q_D(const QQuickTextEdit);
488 void QQuickTextEdit::setHAlign(HAlignment align)
491 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
492 d->hAlignImplicit = false;
493 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
494 d->updateDefaultTextOption();
499 void QQuickTextEdit::resetHAlign()
502 d->hAlignImplicit = true;
503 if (d->determineHorizontalAlignment() && isComponentComplete()) {
504 d->updateDefaultTextOption();
509 QQuickTextEdit::HAlignment QQuickTextEdit::effectiveHAlign() const
511 Q_D(const QQuickTextEdit);
512 QQuickTextEdit::HAlignment effectiveAlignment = d->hAlign;
513 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
515 case QQuickTextEdit::AlignLeft:
516 effectiveAlignment = QQuickTextEdit::AlignRight;
518 case QQuickTextEdit::AlignRight:
519 effectiveAlignment = QQuickTextEdit::AlignLeft;
525 return effectiveAlignment;
528 bool QQuickTextEditPrivate::setHAlign(QQuickTextEdit::HAlignment alignment, bool forceAlign)
531 if (hAlign != alignment || forceAlign) {
532 QQuickTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
534 emit q->horizontalAlignmentChanged(alignment);
535 if (oldEffectiveHAlign != q->effectiveHAlign())
536 emit q->effectiveHorizontalAlignmentChanged();
543 Qt::LayoutDirection QQuickTextEditPrivate::textDirection(const QString &text) const
545 const QChar *character = text.constData();
546 while (!character->isNull()) {
547 switch (character->direction()) {
549 return Qt::LeftToRight;
553 return Qt::RightToLeft;
559 return Qt::LayoutDirectionAuto;
562 bool QQuickTextEditPrivate::determineHorizontalAlignment()
565 if (hAlignImplicit && q->isComponentComplete()) {
566 Qt::LayoutDirection direction = contentDirection;
567 if (direction == Qt::LayoutDirectionAuto) {
568 const QString preeditText = control->textCursor().block().layout()->preeditAreaText();
569 direction = textDirection(preeditText);
571 if (direction == Qt::LayoutDirectionAuto)
572 direction = qGuiApp->inputMethod()->inputDirection();
574 return setHAlign(direction == Qt::RightToLeft ? QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft);
579 void QQuickTextEditPrivate::mirrorChange()
582 if (q->isComponentComplete()) {
583 if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) {
584 updateDefaultTextOption();
586 emit q->effectiveHorizontalAlignmentChanged();
591 QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const
593 Q_D(const QQuickTextEdit);
597 void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment)
600 if (alignment == d->vAlign)
602 d->vAlign = alignment;
603 d->updateDefaultTextOption();
605 moveCursorDelegate();
606 emit verticalAlignmentChanged(d->vAlign);
609 \qmlproperty enumeration QtQuick2::TextEdit::wrapMode
611 Set this property to wrap the text to the TextEdit item's width.
612 The text will only wrap if an explicit width has been set.
615 \li TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
616 \li TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
617 \li TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
618 \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.
621 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
623 QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode() const
625 Q_D(const QQuickTextEdit);
629 void QQuickTextEdit::setWrapMode(WrapMode mode)
632 if (mode == d->wrapMode)
635 d->updateDefaultTextOption();
637 emit wrapModeChanged();
641 \qmlproperty int QtQuick2::TextEdit::lineCount
643 Returns the total number of lines in the textEdit item.
645 int QQuickTextEdit::lineCount() const
647 Q_D(const QQuickTextEdit);
652 \qmlproperty int QtQuick2::TextEdit::length
654 Returns the total number of plain text characters in the TextEdit item.
656 As this number doesn't include any formatting markup it may not be the same as the
657 length of the string returned by the \l text property.
659 This property can be faster than querying the length the \l text property as it doesn't
660 require any copying or conversion of the TextEdit's internal string data.
663 int QQuickTextEdit::length() const
665 Q_D(const QQuickTextEdit);
666 // QTextDocument::characterCount() includes the terminating null character.
667 return qMax(0, d->document->characterCount() - 1);
671 \qmlproperty real QtQuick2::TextEdit::contentWidth
673 Returns the width of the text, including the width past the width
674 which is covered due to insufficient wrapping if \l wrapMode is set.
676 qreal QQuickTextEdit::contentWidth() const
678 Q_D(const QQuickTextEdit);
679 return d->contentSize.width();
683 \qmlproperty real QtQuick2::TextEdit::contentHeight
685 Returns the height of the text, including the height past the height
686 that is covered if the text does not fit within the set height.
688 qreal QQuickTextEdit::contentHeight() const
690 Q_D(const QQuickTextEdit);
691 return d->contentSize.height();
695 \qmlproperty url QtQuick2::TextEdit::baseUrl
697 This property specifies a base URL which is used to resolve relative URLs
700 By default is the url of the TextEdit element.
703 QUrl QQuickTextEdit::baseUrl() const
705 Q_D(const QQuickTextEdit);
706 if (d->baseUrl.isEmpty()) {
707 if (QQmlContext *context = qmlContext(this))
708 const_cast<QQuickTextEditPrivate *>(d)->baseUrl = context->baseUrl();
713 void QQuickTextEdit::setBaseUrl(const QUrl &url)
716 if (baseUrl() != url) {
719 d->document->setBaseUrl(url, d->richText);
720 emit baseUrlChanged();
724 void QQuickTextEdit::resetBaseUrl()
726 if (QQmlContext *context = qmlContext(this))
727 setBaseUrl(context->baseUrl());
733 \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position)
735 Returns the rectangle at the given \a position in the text. The x, y,
736 and height properties correspond to the cursor that would describe
739 QRectF QQuickTextEdit::positionToRectangle(int pos) const
741 Q_D(const QQuickTextEdit);
742 QTextCursor c(d->document);
744 return d->control->cursorRect(c).translated(0, d->yoff);
749 \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y)
751 Returns the text position closest to pixel position (\a x, \a y).
753 Position 0 is before the first character, position 1 is after the first character
754 but before the second, and so on until position \l {text}.length, which is after all characters.
756 int QQuickTextEdit::positionAt(qreal x, qreal y) const
758 Q_D(const QQuickTextEdit);
759 int r = d->document->documentLayout()->hitTest(QPointF(x,y-d->yoff), Qt::FuzzyHit);
760 QTextCursor cursor = d->control->textCursor();
761 if (r > cursor.position()) {
762 // The cursor position includes positions within the preedit text, but only positions in the
763 // same text block are offset so it is possible to get a position that is either part of the
764 // preedit or the next text block.
765 QTextLayout *layout = cursor.block().layout();
766 const int preeditLength = layout
767 ? layout->preeditAreaText().length()
769 if (preeditLength > 0
770 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
771 r = r > cursor.position() + preeditLength
780 \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
782 Moves the cursor to \a position and updates the selection according to the optional \a mode
783 parameter. (To only move the cursor, set the \l cursorPosition property.)
785 When this method is called it additionally sets either the
786 selectionStart or the selectionEnd (whichever was at the previous cursor position)
787 to the specified position. This allows you to easily extend and contract the selected
790 The selection mode specifies whether the selection is updated on a per character or a per word
791 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
794 \li TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
795 the previous cursor position) to the specified position.
796 \li TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
797 words between the specified position and the previous cursor position. Words partially in the
801 For example, take this sequence of calls:
805 moveCursorSelection(9, TextEdit.SelectCharacters)
806 moveCursorSelection(7, TextEdit.SelectCharacters)
809 This moves the cursor to position 5, extend the selection end from 5 to 9
810 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
811 selected (the 6th and 7th characters).
813 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
814 before or on position 5 and extend the selection end to a word boundary on or past position 9.
816 void QQuickTextEdit::moveCursorSelection(int pos)
818 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
820 QTextCursor cursor = d->control->textCursor();
821 if (cursor.position() == pos)
823 cursor.setPosition(pos, QTextCursor::KeepAnchor);
824 d->control->setTextCursor(cursor);
827 void QQuickTextEdit::moveCursorSelection(int pos, SelectionMode mode)
830 QTextCursor cursor = d->control->textCursor();
831 if (cursor.position() == pos)
833 if (mode == SelectCharacters) {
834 cursor.setPosition(pos, QTextCursor::KeepAnchor);
835 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
836 if (cursor.anchor() > cursor.position()) {
837 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
838 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
839 if (cursor.position() == cursor.anchor())
840 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
842 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
844 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
845 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
848 cursor.setPosition(pos, QTextCursor::KeepAnchor);
849 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
850 if (cursor.position() != pos)
851 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
852 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
853 if (cursor.anchor() < cursor.position()) {
854 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
855 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
857 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
858 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
859 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
860 if (cursor.position() != cursor.anchor()) {
861 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
862 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
866 cursor.setPosition(pos, QTextCursor::KeepAnchor);
867 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
868 if (cursor.position() != pos) {
869 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
870 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
873 d->control->setTextCursor(cursor);
877 \qmlproperty bool QtQuick2::TextEdit::cursorVisible
878 If true the text edit shows a cursor.
880 This property is set and unset when the text edit gets active focus, but it can also
881 be set directly (useful, for example, if a KeyProxy might forward keys to it).
883 bool QQuickTextEdit::isCursorVisible() const
885 Q_D(const QQuickTextEdit);
886 return d->cursorVisible;
889 void QQuickTextEdit::setCursorVisible(bool on)
892 if (d->cursorVisible == on)
894 d->cursorVisible = on;
895 if (on && isComponentComplete())
896 QQuickTextUtil::createCursor(d);
897 if (!on && !d->persistentSelection)
898 d->control->setCursorIsFocusIndicator(true);
899 d->control->setCursorVisible(on);
900 emit cursorVisibleChanged(d->cursorVisible);
904 \qmlproperty int QtQuick2::TextEdit::cursorPosition
905 The position of the cursor in the TextEdit.
907 int QQuickTextEdit::cursorPosition() const
909 Q_D(const QQuickTextEdit);
910 return d->control->textCursor().position();
913 void QQuickTextEdit::setCursorPosition(int pos)
916 if (pos < 0 || pos >= d->document->characterCount()) // characterCount includes the terminating null.
918 QTextCursor cursor = d->control->textCursor();
919 if (cursor.position() == pos && cursor.anchor() == pos)
921 cursor.setPosition(pos);
922 d->control->setTextCursor(cursor);
923 d->control->updateCursorRectangle(true);
927 \qmlproperty Component QtQuick2::TextEdit::cursorDelegate
928 The delegate for the cursor in the TextEdit.
930 If you set a cursorDelegate for a TextEdit, this delegate will be used for
931 drawing the cursor instead of the standard cursor. An instance of the
932 delegate will be created and managed by the text edit when a cursor is
933 needed, and the x and y properties of delegate instance will be set so as
934 to be one pixel before the top left of the current character.
936 Note that the root item of the delegate component must be a QQuickItem or
937 QQuickItem derived item.
939 QQmlComponent* QQuickTextEdit::cursorDelegate() const
941 Q_D(const QQuickTextEdit);
942 return d->cursorComponent;
945 void QQuickTextEdit::setCursorDelegate(QQmlComponent* c)
948 QQuickTextUtil::setCursorDelegate(d, c);
951 void QQuickTextEdit::createCursor()
954 d->cursorPending = true;
955 QQuickTextUtil::createCursor(d);
959 \qmlproperty int QtQuick2::TextEdit::selectionStart
961 The cursor position before the first character in the current selection.
963 This property is read-only. To change the selection, use select(start,end),
964 selectAll(), or selectWord().
966 \sa selectionEnd, cursorPosition, selectedText
968 int QQuickTextEdit::selectionStart() const
970 Q_D(const QQuickTextEdit);
971 return d->control->textCursor().selectionStart();
975 \qmlproperty int QtQuick2::TextEdit::selectionEnd
977 The cursor position after the last character in the current selection.
979 This property is read-only. To change the selection, use select(start,end),
980 selectAll(), or selectWord().
982 \sa selectionStart, cursorPosition, selectedText
984 int QQuickTextEdit::selectionEnd() const
986 Q_D(const QQuickTextEdit);
987 return d->control->textCursor().selectionEnd();
991 \qmlproperty string QtQuick2::TextEdit::selectedText
993 This read-only property provides the text currently selected in the
996 It is equivalent to the following snippet, but is faster and easier
999 //myTextEdit is the id of the TextEdit
1000 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
1001 myTextEdit.selectionEnd);
1004 QString QQuickTextEdit::selectedText() const
1006 Q_D(const QQuickTextEdit);
1007 return d->control->textCursor().selectedText();
1011 \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress
1013 Whether the TextEdit should gain active focus on a mouse press. By default this is
1016 bool QQuickTextEdit::focusOnPress() const
1018 Q_D(const QQuickTextEdit);
1019 return d->focusOnPress;
1022 void QQuickTextEdit::setFocusOnPress(bool on)
1024 Q_D(QQuickTextEdit);
1025 if (d->focusOnPress == on)
1027 d->focusOnPress = on;
1028 emit activeFocusOnPressChanged(d->focusOnPress);
1032 \qmlproperty bool QtQuick2::TextEdit::persistentSelection
1034 Whether the TextEdit should keep the selection visible when it loses active focus to another
1035 item in the scene. By default this is set to true;
1037 bool QQuickTextEdit::persistentSelection() const
1039 Q_D(const QQuickTextEdit);
1040 return d->persistentSelection;
1043 void QQuickTextEdit::setPersistentSelection(bool on)
1045 Q_D(QQuickTextEdit);
1046 if (d->persistentSelection == on)
1048 d->persistentSelection = on;
1049 emit persistentSelectionChanged(d->persistentSelection);
1053 \qmlproperty real QtQuick2::TextEdit::textMargin
1055 The margin, in pixels, around the text in the TextEdit.
1057 qreal QQuickTextEdit::textMargin() const
1059 Q_D(const QQuickTextEdit);
1060 return d->textMargin;
1063 void QQuickTextEdit::setTextMargin(qreal margin)
1065 Q_D(QQuickTextEdit);
1066 if (d->textMargin == margin)
1068 d->textMargin = margin;
1069 d->document->setDocumentMargin(d->textMargin);
1070 emit textMarginChanged(d->textMargin);
1074 \qmlproperty enumeration QtQuick2::TextEdit::inputMethodHints
1076 Provides hints to the input method about the expected content of the text edit and how it
1079 The value is a bit-wise combination of flags or Qt.ImhNone if no hints are set.
1081 Flags that alter behaviour are:
1084 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1085 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1086 in any persistent storage like predictive user dictionary.
1087 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1088 when a sentence ends.
1089 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1090 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1091 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1092 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1094 \li Qt.ImhDate - The text editor functions as a date field.
1095 \li Qt.ImhTime - The text editor functions as a time field.
1098 Flags that restrict input (exclusive flags) are:
1101 \li Qt.ImhDigitsOnly - Only digits are allowed.
1102 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1103 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1104 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1105 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1106 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1107 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1113 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1117 Qt::InputMethodHints QQuickTextEdit::inputMethodHints() const
1119 Q_D(const QQuickTextEdit);
1120 return d->inputMethodHints;
1123 void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints)
1125 Q_D(QQuickTextEdit);
1127 if (hints == d->inputMethodHints)
1130 d->inputMethodHints = hints;
1131 updateInputMethod(Qt::ImHints);
1132 emit inputMethodHintsChanged();
1135 void QQuickTextEdit::geometryChanged(const QRectF &newGeometry,
1136 const QRectF &oldGeometry)
1138 Q_D(QQuickTextEdit);
1139 if (newGeometry.width() != oldGeometry.width() && widthValid() && !d->inLayout) {
1141 moveCursorDelegate();
1143 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1148 Ensures any delayed caching or data loading the class
1149 needs to performed is complete.
1151 void QQuickTextEdit::componentComplete()
1153 Q_D(QQuickTextEdit);
1154 QQuickImplicitSizeItem::componentComplete();
1156 d->document->setBaseUrl(baseUrl(), d->richText);
1158 d->determineHorizontalAlignment();
1159 d->updateDefaultTextOption();
1163 if (d->cursorComponent && isCursorVisible())
1164 QQuickTextUtil::createCursor(d);
1167 \qmlproperty bool QtQuick2::TextEdit::selectByMouse
1171 If true, the user can use the mouse to select text in some
1172 platform-specific way. Note that for some platforms this may
1173 not be an appropriate interaction (eg. may conflict with how
1174 the text needs to behave inside a Flickable.
1176 bool QQuickTextEdit::selectByMouse() const
1178 Q_D(const QQuickTextEdit);
1179 return d->selectByMouse;
1182 void QQuickTextEdit::setSelectByMouse(bool on)
1184 Q_D(QQuickTextEdit);
1185 if (d->selectByMouse != on) {
1186 d->selectByMouse = on;
1187 setKeepMouseGrab(on);
1189 setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1191 setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1192 emit selectByMouseChanged(on);
1197 \qmlproperty enum QtQuick2::TextEdit::mouseSelectionMode
1199 Specifies how text should be selected using a mouse.
1202 \li TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1203 \li TextEdit.SelectWords - The selection is updated with whole words.
1206 This property only applies when \l selectByMouse is true.
1208 QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode() const
1210 Q_D(const QQuickTextEdit);
1211 return d->mouseSelectionMode;
1214 void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode)
1216 Q_D(QQuickTextEdit);
1217 if (d->mouseSelectionMode != mode) {
1218 d->mouseSelectionMode = mode;
1219 d->control->setWordSelectionEnabled(mode == SelectWords);
1220 emit mouseSelectionModeChanged(mode);
1225 \qmlproperty bool QtQuick2::TextEdit::readOnly
1227 Whether the user can interact with the TextEdit item. If this
1228 property is set to true the text cannot be edited by user interaction.
1230 By default this property is false.
1232 void QQuickTextEdit::setReadOnly(bool r)
1234 Q_D(QQuickTextEdit);
1235 if (r == isReadOnly())
1238 setFlag(QQuickItem::ItemAcceptsInputMethod, !r);
1239 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1240 if (d->selectByMouse)
1241 flags = flags | Qt::TextSelectableByMouse;
1243 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1244 d->control->setTextInteractionFlags(flags);
1246 d->control->moveCursor(QTextCursor::End);
1248 updateInputMethod(Qt::ImEnabled);
1249 q_canPasteChanged();
1250 emit readOnlyChanged(r);
1253 bool QQuickTextEdit::isReadOnly() const
1255 Q_D(const QQuickTextEdit);
1256 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1260 Sets how the text edit should interact with user input to the given
1263 void QQuickTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1265 Q_D(QQuickTextEdit);
1266 d->control->setTextInteractionFlags(flags);
1270 Returns the flags specifying how the text edit should interact
1273 Qt::TextInteractionFlags QQuickTextEdit::textInteractionFlags() const
1275 Q_D(const QQuickTextEdit);
1276 return d->control->textInteractionFlags();
1280 \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle
1282 The rectangle where the standard text cursor is rendered
1283 within the text edit. Read-only.
1285 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
1286 automatically when it changes. The width of the delegate is unaffected by changes in the
1289 QRectF QQuickTextEdit::cursorRectangle() const
1291 Q_D(const QQuickTextEdit);
1292 return d->control->cursorRect().translated(0, d->yoff);
1295 bool QQuickTextEdit::event(QEvent *event)
1297 Q_D(QQuickTextEdit);
1298 if (event->type() == QEvent::ShortcutOverride) {
1299 d->control->processEvent(event, QPointF(0, -d->yoff));
1300 return event->isAccepted();
1302 return QQuickImplicitSizeItem::event(event);
1307 Handles the given key \a event.
1309 void QQuickTextEdit::keyPressEvent(QKeyEvent *event)
1311 Q_D(QQuickTextEdit);
1312 d->control->processEvent(event, QPointF(0, -d->yoff));
1313 if (!event->isAccepted())
1314 QQuickImplicitSizeItem::keyPressEvent(event);
1319 Handles the given key \a event.
1321 void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event)
1323 Q_D(QQuickTextEdit);
1324 d->control->processEvent(event, QPointF(0, -d->yoff));
1325 if (!event->isAccepted())
1326 QQuickImplicitSizeItem::keyReleaseEvent(event);
1330 \qmlmethod void QtQuick2::TextEdit::deselect()
1332 Removes active text selection.
1334 void QQuickTextEdit::deselect()
1336 Q_D(QQuickTextEdit);
1337 QTextCursor c = d->control->textCursor();
1339 d->control->setTextCursor(c);
1343 \qmlmethod void QtQuick2::TextEdit::selectAll()
1345 Causes all text to be selected.
1347 void QQuickTextEdit::selectAll()
1349 Q_D(QQuickTextEdit);
1350 d->control->selectAll();
1354 \qmlmethod void QtQuick2::TextEdit::selectWord()
1356 Causes the word closest to the current cursor position to be selected.
1358 void QQuickTextEdit::selectWord()
1360 Q_D(QQuickTextEdit);
1361 QTextCursor c = d->control->textCursor();
1362 c.select(QTextCursor::WordUnderCursor);
1363 d->control->setTextCursor(c);
1367 \qmlmethod void QtQuick2::TextEdit::select(int start, int end)
1369 Causes the text from \a start to \a end to be selected.
1371 If either start or end is out of range, the selection is not changed.
1373 After calling this, selectionStart will become the lesser
1374 and selectionEnd will become the greater (regardless of the order passed
1377 \sa selectionStart, selectionEnd
1379 void QQuickTextEdit::select(int start, int end)
1381 Q_D(QQuickTextEdit);
1382 if (start < 0 || end < 0 || start >= d->document->characterCount() || end >= d->document->characterCount())
1384 QTextCursor cursor = d->control->textCursor();
1385 cursor.beginEditBlock();
1386 cursor.setPosition(start, QTextCursor::MoveAnchor);
1387 cursor.setPosition(end, QTextCursor::KeepAnchor);
1388 cursor.endEditBlock();
1389 d->control->setTextCursor(cursor);
1392 updateSelectionMarkers();
1396 \qmlmethod void QtQuick2::TextEdit::isRightToLeft(int start, int end)
1398 Returns true if the natural reading direction of the editor text
1399 found between positions \a start and \a end is right to left.
1401 bool QQuickTextEdit::isRightToLeft(int start, int end)
1404 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1407 return getText(start, end).isRightToLeft();
1411 #ifndef QT_NO_CLIPBOARD
1413 \qmlmethod QtQuick2::TextEdit::cut()
1415 Moves the currently selected text to the system clipboard.
1417 void QQuickTextEdit::cut()
1419 Q_D(QQuickTextEdit);
1424 \qmlmethod QtQuick2::TextEdit::copy()
1426 Copies the currently selected text to the system clipboard.
1428 void QQuickTextEdit::copy()
1430 Q_D(QQuickTextEdit);
1435 \qmlmethod QtQuick2::TextEdit::paste()
1437 Replaces the currently selected text by the contents of the system clipboard.
1439 void QQuickTextEdit::paste()
1441 Q_D(QQuickTextEdit);
1442 d->control->paste();
1444 #endif // QT_NO_CLIPBOARD
1448 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1449 current selection, and updates the selection start to the current cursor
1453 void QQuickTextEdit::undo()
1455 Q_D(QQuickTextEdit);
1460 Redoes the last operation if redo is \l {canRedo}{available}.
1463 void QQuickTextEdit::redo()
1465 Q_D(QQuickTextEdit);
1471 Handles the given mouse \a event.
1473 void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
1475 Q_D(QQuickTextEdit);
1476 d->control->processEvent(event, QPointF(0, -d->yoff));
1477 if (d->focusOnPress){
1478 bool hadActiveFocus = hasActiveFocus();
1480 // re-open input panel on press if already focused
1481 if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
1482 openSoftwareInputPanel();
1484 if (!event->isAccepted())
1485 QQuickImplicitSizeItem::mousePressEvent(event);
1490 Handles the given mouse \a event.
1492 void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
1494 Q_D(QQuickTextEdit);
1495 d->control->processEvent(event, QPointF(0, -d->yoff));
1497 if (!event->isAccepted())
1498 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1503 Handles the given mouse \a event.
1505 void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
1507 Q_D(QQuickTextEdit);
1508 d->control->processEvent(event, QPointF(0, -d->yoff));
1509 if (!event->isAccepted())
1510 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1515 Handles the given mouse \a event.
1517 void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
1519 Q_D(QQuickTextEdit);
1520 d->control->processEvent(event, QPointF(0, -d->yoff));
1521 if (!event->isAccepted())
1522 QQuickImplicitSizeItem::mouseMoveEvent(event);
1527 Handles the given input method \a event.
1529 void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
1531 Q_D(QQuickTextEdit);
1532 const bool wasComposing = isInputMethodComposing();
1533 d->control->processEvent(event, QPointF(0, -d->yoff));
1534 setCursorVisible(d->control->cursorVisible());
1535 if (wasComposing != isInputMethodComposing())
1536 emit inputMethodComposingChanged();
1539 void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1541 Q_D(QQuickTextEdit);
1542 if (change == ItemActiveFocusHasChanged) {
1543 setCursorVisible(value.boolValue); // ### refactor: focus handling && d->canvas && d->canvas->hasFocus());
1544 QFocusEvent focusEvent(value.boolValue ? QEvent::FocusIn : QEvent::FocusOut);
1545 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
1546 if (value.boolValue) {
1547 q_updateAlignment();
1548 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1549 this, SLOT(q_updateAlignment()));
1551 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1552 this, SLOT(q_updateAlignment()));
1555 QQuickItem::itemChange(change, value);
1560 Returns the value of the given \a property.
1562 QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1564 Q_D(const QQuickTextEdit);
1569 v = (bool)(flags() & ItemAcceptsInputMethod);
1572 v = (int)inputMethodHints();
1575 v = d->control->inputMethodQuery(property);
1582 void QQuickTextEdit::triggerPreprocess()
1584 Q_D(QQuickTextEdit);
1585 if (d->updateType == QQuickTextEditPrivate::UpdateNone)
1586 d->updateType = QQuickTextEditPrivate::UpdateOnlyPreprocess;
1590 QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1592 Q_UNUSED(updatePaintNodeData);
1593 Q_D(QQuickTextEdit);
1595 if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode && oldNode != 0) {
1596 // Update done in preprocess() in the nodes
1597 d->updateType = QQuickTextEditPrivate::UpdateNone;
1601 d->updateType = QQuickTextEditPrivate::UpdateNone;
1603 QSGNode *currentNode = oldNode;
1604 if (oldNode == 0 || d->documentDirty) {
1605 d->documentDirty = false;
1607 #if defined(Q_OS_MAC)
1608 // Make sure document is relayouted in the paint node on Mac
1609 // to avoid crashes due to the font engines created in the
1611 d->document->markContentsDirty(0, d->document->characterCount());
1614 QQuickTextNode *node = 0;
1616 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1619 node = static_cast<QQuickTextNode *>(oldNode);
1622 node->deleteContent();
1623 node->setMatrix(QMatrix4x4());
1625 QRectF bounds = boundingRect();
1627 node->addTextDocument(bounds.topLeft(), d->document, d->color, QQuickText::Normal, QColor(),
1628 QColor(), d->selectionColor, d->selectedTextColor, selectionStart(),
1629 selectionEnd() - 1); // selectionEnd() returns first char after
1632 #if defined(Q_OS_MAC)
1633 // We also need to make sure the document layout is redone when
1634 // control is returned to the main thread, as all the font engines
1635 // are now owned by the rendering thread
1636 d->document->markContentsDirty(0, d->document->characterCount());
1640 if (d->cursorComponent == 0 && !isReadOnly()) {
1641 QQuickTextNode *node = static_cast<QQuickTextNode *>(currentNode);
1643 QColor color = (!d->cursorVisible || !d->control->cursorOn())
1644 ? QColor(0, 0, 0, 0)
1647 if (node->cursorNode() == 0) {
1648 node->setCursor(cursorRectangle(), color);
1650 node->cursorNode()->setRect(cursorRectangle());
1651 node->cursorNode()->setColor(color);
1660 \qmlproperty bool QtQuick2::TextEdit::smooth
1662 This property holds whether the text is smoothly scaled or transformed.
1664 Smooth filtering gives better visual quality, but is slower. If
1665 the item is displayed at its natural size, this property has no visual or
1668 \note Generally scaling artifacts are only visible if the item is stationary on
1669 the screen. A common pattern when animating an item is to disable smooth
1670 filtering at the beginning of the animation and reenable it at the conclusion.
1674 \qmlproperty bool QtQuick2::TextEdit::canPaste
1676 Returns true if the TextEdit is writable and the content of the clipboard is
1677 suitable for pasting into the TextEdit.
1679 bool QQuickTextEdit::canPaste() const
1681 Q_D(const QQuickTextEdit);
1682 if (!d->canPasteValid) {
1683 const_cast<QQuickTextEditPrivate *>(d)->canPaste = d->control->canPaste();
1684 const_cast<QQuickTextEditPrivate *>(d)->canPasteValid = true;
1690 \qmlproperty bool QtQuick2::TextEdit::canUndo
1692 Returns true if the TextEdit is writable and there are previous operations
1696 bool QQuickTextEdit::canUndo() const
1698 Q_D(const QQuickTextEdit);
1699 return d->document->isUndoAvailable();
1703 \qmlproperty bool QtQuick2::TextEdit::canRedo
1705 Returns true if the TextEdit is writable and there are \l {undo}{undone}
1706 operations that can be redone.
1709 bool QQuickTextEdit::canRedo() const
1711 Q_D(const QQuickTextEdit);
1712 return d->document->isRedoAvailable();
1716 \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1719 This property holds whether the TextEdit has partial text input from an
1722 While it is composing an input method may rely on mouse or key events from
1723 the TextEdit to edit or commit the partial text. This property can be used
1724 to determine when to disable events handlers that may interfere with the
1725 correct operation of an input method.
1727 bool QQuickTextEdit::isInputMethodComposing() const
1729 Q_D(const QQuickTextEdit);
1730 return d->control->hasImState();
1733 void QQuickTextEditPrivate::init()
1735 Q_Q(QQuickTextEdit);
1737 q->setSmooth(smooth);
1738 q->setAcceptedMouseButtons(Qt::LeftButton);
1739 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1740 q->setFlag(QQuickItem::ItemHasContents);
1742 document = new QQuickTextDocumentWithImageResources(q);
1744 control = new QQuickTextControl(document, q);
1745 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1746 control->setAcceptRichText(false);
1747 control->setCursorIsFocusIndicator(true);
1749 FAST_CONNECT(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateDocument()));
1750 FAST_CONNECT(control, SIGNAL(updateCursorRequest()), q, SLOT(updateCursor()));
1751 FAST_CONNECT(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1752 FAST_CONNECT(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1753 FAST_CONNECT(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1754 FAST_CONNECT(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1755 FAST_CONNECT(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1756 FAST_CONNECT(control, SIGNAL(cursorRectangleChanged()), q, SLOT(moveCursorDelegate()));
1757 FAST_CONNECT(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1758 #ifndef QT_NO_CLIPBOARD
1759 FAST_CONNECT(QGuiApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1761 FAST_CONNECT(document, SIGNAL(undoAvailable(bool)), q, SIGNAL(canUndoChanged()));
1762 FAST_CONNECT(document, SIGNAL(redoAvailable(bool)), q, SIGNAL(canRedoChanged()));
1763 FAST_CONNECT(document, SIGNAL(imagesLoaded()), q, SLOT(updateSize()));
1765 document->setDefaultFont(font);
1766 document->setDocumentMargin(textMargin);
1767 document->setUndoRedoEnabled(false); // flush undo buffer.
1768 document->setUndoRedoEnabled(true);
1769 updateDefaultTextOption();
1772 void QQuickTextEdit::q_textChanged()
1774 Q_D(QQuickTextEdit);
1775 d->textCached = false;
1776 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1777 d->contentDirection = d->textDirection(it.text());
1778 if (d->contentDirection != Qt::LayoutDirectionAuto)
1781 d->determineHorizontalAlignment();
1782 d->updateDefaultTextOption();
1788 void QQuickTextEdit::moveCursorDelegate()
1790 Q_D(QQuickTextEdit);
1791 d->determineHorizontalAlignment();
1792 updateInputMethod();
1793 emit cursorRectangleChanged();
1796 QRectF cursorRect = cursorRectangle();
1797 d->cursorItem->setX(cursorRect.x());
1798 d->cursorItem->setY(cursorRect.y());
1801 void QQuickTextEdit::updateSelectionMarkers()
1803 Q_D(QQuickTextEdit);
1804 if (d->lastSelectionStart != d->control->textCursor().selectionStart()) {
1805 d->lastSelectionStart = d->control->textCursor().selectionStart();
1806 emit selectionStartChanged();
1808 if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) {
1809 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1810 emit selectionEndChanged();
1814 QRectF QQuickTextEdit::boundingRect() const
1816 Q_D(const QQuickTextEdit);
1817 QRectF r(0, -d->yoff, d->contentSize.width(), d->contentSize.height());
1818 int cursorWidth = 1;
1821 else if (!d->document->isEmpty())
1822 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1824 // Could include font max left/right bearings to either side of rectangle.
1826 r.setRight(r.right() + cursorWidth);
1829 switch (d->vAlign) {
1833 r.moveTop(h - r.height());
1836 r.moveTop((h - r.height()) / 2);
1841 switch (d->hAlign) {
1846 r.moveLeft(w - r.width());
1849 r.moveLeft((w - r.width()) / 2);
1856 QRectF QQuickTextEdit::clipRect() const
1858 Q_D(const QQuickTextEdit);
1859 QRectF r = QQuickImplicitSizeItem::clipRect();
1860 int cursorWidth = 1;
1862 cursorWidth = d->cursorItem->width();
1863 if (!d->document->isEmpty())
1864 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1866 // Could include font max left/right bearings to either side of rectangle.
1868 r.setRight(r.right() + cursorWidth);
1872 qreal QQuickTextEditPrivate::getImplicitWidth() const
1874 Q_Q(const QQuickTextEdit);
1875 if (!requireImplicitWidth) {
1876 // We don't calculate implicitWidth unless it is required.
1877 // We need to force a size update now to ensure implicitWidth is calculated
1878 const_cast<QQuickTextEditPrivate*>(this)->requireImplicitWidth = true;
1879 const_cast<QQuickTextEdit*>(q)->updateSize();
1881 return implicitWidth;
1884 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1885 // need to do all the calculations each time
1886 void QQuickTextEdit::updateSize()
1888 Q_D(QQuickTextEdit);
1889 if (isComponentComplete()) {
1890 qreal naturalWidth = d->implicitWidth;
1891 // ### assumes that if the width is set, the text will fill to edges
1892 // ### (unless wrap is false, then clipping will occur)
1894 if (!d->requireImplicitWidth) {
1895 emit implicitWidthChanged();
1896 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1897 if (d->requireImplicitWidth)
1900 if (d->requireImplicitWidth) {
1901 d->document->setTextWidth(-1);
1902 naturalWidth = d->document->idealWidth();
1904 const bool wasInLayout = d->inLayout;
1906 setImplicitWidth(naturalWidth);
1907 d->inLayout = wasInLayout;
1908 if (d->inLayout) // probably the result of a binding loop, but by letting it
1909 return; // get this far we'll get a warning to that effect.
1911 if (d->document->textWidth() != width())
1912 d->document->setTextWidth(width());
1914 d->document->setTextWidth(-1);
1916 QFontMetricsF fm(d->font);
1917 qreal dy = height();
1918 dy -= d->document->size().height();
1921 if (heightValid()) {
1922 if (d->vAlign == AlignBottom)
1924 else if (d->vAlign == AlignVCenter)
1931 if (nyoff != d->yoff)
1933 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1935 //### need to comfirm cost of always setting these
1936 qreal newWidth = d->document->idealWidth();
1937 if (!widthValid() && d->document->textWidth() != newWidth)
1938 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1939 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1941 if (!widthValid() && !d->requireImplicitWidth)
1944 qreal newHeight = d->document->isEmpty() ? qCeil(fm.height()) : d->document->size().height();
1947 setImplicitSize(iWidth, newHeight);
1949 setImplicitHeight(newHeight);
1951 QSizeF size(newWidth, newHeight);
1952 if (d->contentSize != size) {
1953 d->contentSize = size;
1954 emit contentSizeChanged();
1962 void QQuickTextEdit::updateDocument()
1964 Q_D(QQuickTextEdit);
1965 d->documentDirty = true;
1967 if (isComponentComplete()) {
1968 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1973 void QQuickTextEdit::updateCursor()
1975 Q_D(QQuickTextEdit);
1976 if (isComponentComplete()) {
1977 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1982 void QQuickTextEdit::q_updateAlignment()
1984 Q_D(QQuickTextEdit);
1985 if (d->determineHorizontalAlignment()) {
1986 d->updateDefaultTextOption();
1987 moveCursorDelegate();
1991 void QQuickTextEdit::updateTotalLines()
1993 Q_D(QQuickTextEdit);
1997 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1998 QTextLayout *layout = it.layout();
2001 subLines += layout->lineCount()-1;
2004 int newTotalLines = d->document->lineCount() + subLines;
2005 if (d->lineCount != newTotalLines) {
2006 d->lineCount = newTotalLines;
2007 emit lineCountChanged();
2011 void QQuickTextEditPrivate::updateDefaultTextOption()
2013 Q_Q(QQuickTextEdit);
2014 QTextOption opt = document->defaultTextOption();
2015 int oldAlignment = opt.alignment();
2016 Qt::LayoutDirection oldTextDirection = opt.textDirection();
2018 QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
2019 if (contentDirection == Qt::RightToLeft) {
2020 if (horizontalAlignment == QQuickTextEdit::AlignLeft)
2021 horizontalAlignment = QQuickTextEdit::AlignRight;
2022 else if (horizontalAlignment == QQuickTextEdit::AlignRight)
2023 horizontalAlignment = QQuickTextEdit::AlignLeft;
2025 if (!hAlignImplicit)
2026 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
2028 opt.setAlignment(Qt::Alignment(vAlign));
2030 if (contentDirection == Qt::LayoutDirectionAuto) {
2031 opt.setTextDirection(qGuiApp->inputMethod()->inputDirection());
2033 opt.setTextDirection(contentDirection);
2036 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
2037 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
2038 opt.setUseDesignMetrics(true);
2040 if (oldWrapMode != opt.wrapMode() || oldAlignment != opt.alignment()
2041 || oldTextDirection != opt.textDirection()) {
2042 document->setDefaultTextOption(opt);
2049 \qmlmethod void QtQuick2::TextEdit::openSoftwareInputPanel()
2051 Opens software input panels like virtual keyboards for typing, useful for
2052 customizing when you want the input keyboard to be shown and hidden in
2055 By default the opening of input panels follows the platform style. Input panels are
2056 always closed if no editor has active focus.
2058 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2059 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2060 the behavior you want.
2062 Only relevant on platforms, which provide virtual keyboards.
2068 text: "Hello world!"
2069 activeFocusOnPress: false
2071 anchors.fill: parent
2073 if (!textEdit.activeFocus) {
2074 textEdit.forceActiveFocus();
2075 textEdit.openSoftwareInputPanel();
2077 textEdit.focus = false;
2080 onPressAndHold: textEdit.closeSoftwareInputPanel();
2085 void QQuickTextEdit::openSoftwareInputPanel()
2088 qGuiApp->inputMethod()->show();
2092 \qmlmethod void QtQuick2::TextEdit::closeSoftwareInputPanel()
2094 Closes a software input panel like a virtual keyboard shown on the screen, useful
2095 for customizing when you want the input keyboard to be shown and hidden in
2098 By default the opening of input panels follows the platform style. Input panels are
2099 always closed if no editor has active focus.
2101 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2102 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2103 the behavior you want.
2105 Only relevant on platforms, which provide virtual keyboards.
2111 text: "Hello world!"
2112 activeFocusOnPress: false
2114 anchors.fill: parent
2116 if (!textEdit.activeFocus) {
2117 textEdit.forceActiveFocus();
2118 textEdit.openSoftwareInputPanel();
2120 textEdit.focus = false;
2123 onPressAndHold: textEdit.closeSoftwareInputPanel();
2128 void QQuickTextEdit::closeSoftwareInputPanel()
2131 qGuiApp->inputMethod()->hide();
2134 void QQuickTextEdit::focusInEvent(QFocusEvent *event)
2136 Q_D(const QQuickTextEdit);
2137 if (d->focusOnPress && !isReadOnly())
2138 openSoftwareInputPanel();
2139 QQuickImplicitSizeItem::focusInEvent(event);
2142 void QQuickTextEdit::q_canPasteChanged()
2144 Q_D(QQuickTextEdit);
2145 bool old = d->canPaste;
2146 d->canPaste = d->control->canPaste();
2147 bool changed = old!=d->canPaste || !d->canPasteValid;
2148 d->canPasteValid = true;
2150 emit canPasteChanged();
2154 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2156 Returns the section of text that is between the \a start and \a end positions.
2158 The returned text does not include any rich text formatting.
2161 QString QQuickTextEdit::getText(int start, int end) const
2163 Q_D(const QQuickTextEdit);
2164 start = qBound(0, start, d->document->characterCount() - 1);
2165 end = qBound(0, end, d->document->characterCount() - 1);
2166 QTextCursor cursor(d->document);
2167 cursor.setPosition(start, QTextCursor::MoveAnchor);
2168 cursor.setPosition(end, QTextCursor::KeepAnchor);
2169 return cursor.selectedText();
2173 \qmlmethod string QtQuick2::TextEdit::getFormattedText(int start, int end)
2175 Returns the section of text that is between the \a start and \a end positions.
2177 The returned text will be formatted according the \l textFormat property.
2180 QString QQuickTextEdit::getFormattedText(int start, int end) const
2182 Q_D(const QQuickTextEdit);
2184 start = qBound(0, start, d->document->characterCount() - 1);
2185 end = qBound(0, end, d->document->characterCount() - 1);
2187 QTextCursor cursor(d->document);
2188 cursor.setPosition(start, QTextCursor::MoveAnchor);
2189 cursor.setPosition(end, QTextCursor::KeepAnchor);
2192 #ifndef QT_NO_TEXTHTMLPARSER
2193 return cursor.selection().toHtml();
2195 return cursor.selection().toPlainText();
2198 return cursor.selection().toPlainText();
2203 \qmlmethod void QtQuick2::TextEdit::insert(int position, string text)
2205 Inserts \a text into the TextEdit at position.
2207 void QQuickTextEdit::insert(int position, const QString &text)
2209 Q_D(QQuickTextEdit);
2210 if (position < 0 || position >= d->document->characterCount())
2212 QTextCursor cursor(d->document);
2213 cursor.setPosition(position);
2214 d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text));
2216 #ifndef QT_NO_TEXTHTMLPARSER
2217 cursor.insertHtml(text);
2219 cursor.insertText(text);
2222 cursor.insertText(text);
2224 d->control->updateCursorRectangle(false);
2228 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2230 Removes the section of text that is between the \a start and \a end positions from the TextEdit.
2233 void QQuickTextEdit::remove(int start, int end)
2235 Q_D(QQuickTextEdit);
2236 start = qBound(0, start, d->document->characterCount() - 1);
2237 end = qBound(0, end, d->document->characterCount() - 1);
2238 QTextCursor cursor(d->document);
2239 cursor.setPosition(start, QTextCursor::MoveAnchor);
2240 cursor.setPosition(end, QTextCursor::KeepAnchor);
2241 cursor.removeSelectedText();
2242 d->control->updateCursorRectangle(false);