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 <QtQuick/qsgsimplerectnode.h>
51 #include <QtQml/qqmlinfo.h>
52 #include <QtGui/qguiapplication.h>
53 #include <QtGui/qevent.h>
54 #include <QtGui/qpainter.h>
55 #include <QtGui/qtextobject.h>
56 #include <QtCore/qmath.h>
58 #include <private/qqmlglobal_p.h>
59 #include <private/qqmlproperty_p.h>
60 #include <private/qtextengine_p.h>
61 #include <private/qsgadaptationlayer_p.h>
66 \qmlclass TextEdit QQuickTextEdit
67 \inqmlmodule QtQuick 2
68 \ingroup qml-basic-visual-elements
69 \brief The TextEdit item displays multiple lines of editable formatted text.
72 The TextEdit item displays a block of editable, formatted text.
74 It can display both plain and rich text. For example:
79 text: "<b>Hello</b> <i>World!</i>"
80 font.family: "Helvetica"
87 \image declarative-textedit.gif
89 Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
91 Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
92 to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
94 \snippet snippets/declarative/texteditor.qml 0
96 A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible
97 scrollbar, or a scrollbar that fades in to show location, etc.
99 Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
100 be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
101 from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
103 You can translate between cursor positions (characters from the start of the document) and pixel
104 points using positionAt() and positionToRectangle().
106 \sa Text, TextInput, {declarative/text/textselection}{Text Selection example}
110 \qmlsignal QtQuick2::TextEdit::onLinkActivated(string link)
112 This handler is called when the user clicks on a link embedded in the text.
113 The link must be in rich text or HTML format and the
114 \a link string provides access to the particular link.
116 QQuickTextEdit::QQuickTextEdit(QQuickItem *parent)
117 : QQuickImplicitSizeItem(*(new QQuickTextEditPrivate), parent)
123 QString QQuickTextEdit::text() const
125 Q_D(const QQuickTextEdit);
126 if (!d->textCached) {
127 QQuickTextEditPrivate *d = const_cast<QQuickTextEditPrivate *>(d_func());
128 #ifndef QT_NO_TEXTHTMLPARSER
130 d->text = d->control->toHtml();
133 d->text = d->control->toPlainText();
134 d->textCached = true;
140 \qmlproperty string QtQuick2::TextEdit::font.family
142 Sets the family name of the font.
144 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
145 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
146 If the family isn't available a family will be set using the font matching algorithm.
150 \qmlproperty bool QtQuick2::TextEdit::font.bold
152 Sets whether the font weight is bold.
156 \qmlproperty enumeration QtQuick2::TextEdit::font.weight
158 Sets the font's weight.
160 The weight can be one of:
163 \li Font.Normal - the default
170 TextEdit { text: "Hello"; font.weight: Font.DemiBold }
175 \qmlproperty bool QtQuick2::TextEdit::font.italic
177 Sets whether the font has an italic style.
181 \qmlproperty bool QtQuick2::TextEdit::font.underline
183 Sets whether the text is underlined.
187 \qmlproperty bool QtQuick2::TextEdit::font.strikeout
189 Sets whether the font has a strikeout style.
193 \qmlproperty real QtQuick2::TextEdit::font.pointSize
195 Sets the font size in points. The point size must be greater than zero.
199 \qmlproperty int QtQuick2::TextEdit::font.pixelSize
201 Sets the font size in pixels.
203 Using this function makes the font device dependent. Use
204 \l{TextEdit::font.pointSize} to set the size of the font in a
205 device independent manner.
209 \qmlproperty real QtQuick2::TextEdit::font.letterSpacing
211 Sets the letter spacing for the font.
213 Letter spacing changes the default spacing between individual letters in the font.
214 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
218 \qmlproperty real QtQuick2::TextEdit::font.wordSpacing
220 Sets the word spacing for the font.
222 Word spacing changes the default spacing between individual words.
223 A positive value increases the word spacing by a corresponding amount of pixels,
224 while a negative value decreases the inter-word spacing accordingly.
228 \qmlproperty enumeration QtQuick2::TextEdit::font.capitalization
230 Sets the capitalization for the text.
233 \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
234 \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
235 \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
236 \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
237 \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
241 TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
246 \qmlproperty string QtQuick2::TextEdit::text
248 The text to display. If the text format is AutoText the text edit will
249 automatically determine whether the text should be treated as
250 rich text. This determination is made using Qt::mightBeRichText().
252 void QQuickTextEdit::setText(const QString &text)
255 if (QQuickTextEdit::text() == text)
258 d->document->clearResources();
259 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
261 #ifndef QT_NO_TEXTHTMLPARSER
262 d->control->setHtml(text);
264 d->control->setPlainText(text);
267 d->control->setPlainText(text);
272 \qmlproperty enumeration QtQuick2::TextEdit::textFormat
274 The way the text property should be displayed.
277 \li TextEdit.AutoText
278 \li TextEdit.PlainText
279 \li TextEdit.RichText
282 The default is TextEdit.PlainText. If the text format is TextEdit.AutoText the text edit
283 will automatically determine whether the text should be treated as
284 rich text. This determination is made using Qt::mightBeRichText().
293 text: "<b>Hello</b> <i>World!</i>"
297 textFormat: TextEdit.RichText
298 text: "<b>Hello</b> <i>World!</i>"
302 textFormat: TextEdit.PlainText
303 text: "<b>Hello</b> <i>World!</i>"
307 \li \image declarative-textformat.png
310 QQuickTextEdit::TextFormat QQuickTextEdit::textFormat() const
312 Q_D(const QQuickTextEdit);
316 void QQuickTextEdit::setTextFormat(TextFormat format)
319 if (format == d->format)
322 bool wasRich = d->richText;
323 d->richText = format == RichText || (format == AutoText && (wasRich || Qt::mightBeRichText(text())));
325 #ifndef QT_NO_TEXTHTMLPARSER
326 if (wasRich && !d->richText) {
327 d->control->setPlainText(!d->textCached ? d->control->toHtml() : d->text);
329 } else if (!wasRich && d->richText) {
330 d->control->setHtml(!d->textCached ? d->control->toPlainText() : d->text);
336 d->control->setAcceptRichText(d->format != PlainText);
337 emit textFormatChanged(d->format);
340 QFont QQuickTextEdit::font() const
342 Q_D(const QQuickTextEdit);
343 return d->sourceFont;
346 void QQuickTextEdit::setFont(const QFont &font)
349 if (d->sourceFont == font)
352 d->sourceFont = font;
353 QFont oldFont = d->font;
355 if (d->font.pointSizeF() != -1) {
357 qreal size = qRound(d->font.pointSizeF()*2.0);
358 d->font.setPointSizeF(size/2.0);
361 if (oldFont != d->font) {
362 d->document->setDefaultFont(d->font);
364 d->cursor->setHeight(QFontMetrics(d->font).height());
365 moveCursorDelegate();
369 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
371 emit fontChanged(d->sourceFont);
375 \qmlproperty color QtQuick2::TextEdit::color
380 // green text using hexadecimal notation
381 TextEdit { color: "#00FF00" }
385 // steelblue text using SVG color name
386 TextEdit { color: "steelblue" }
389 QColor QQuickTextEdit::color() const
391 Q_D(const QQuickTextEdit);
395 void QQuickTextEdit::setColor(const QColor &color)
398 if (d->color == color)
403 emit colorChanged(d->color);
407 \qmlproperty color QtQuick2::TextEdit::selectionColor
409 The text highlight color, used behind selections.
411 QColor QQuickTextEdit::selectionColor() const
413 Q_D(const QQuickTextEdit);
414 return d->selectionColor;
417 void QQuickTextEdit::setSelectionColor(const QColor &color)
420 if (d->selectionColor == color)
423 d->selectionColor = color;
425 emit selectionColorChanged(d->selectionColor);
429 \qmlproperty color QtQuick2::TextEdit::selectedTextColor
431 The selected text color, used in selections.
433 QColor QQuickTextEdit::selectedTextColor() const
435 Q_D(const QQuickTextEdit);
436 return d->selectedTextColor;
439 void QQuickTextEdit::setSelectedTextColor(const QColor &color)
442 if (d->selectedTextColor == color)
445 d->selectedTextColor = color;
447 emit selectedTextColorChanged(d->selectedTextColor);
451 \qmlproperty enumeration QtQuick2::TextEdit::horizontalAlignment
452 \qmlproperty enumeration QtQuick2::TextEdit::verticalAlignment
453 \qmlproperty enumeration QtQuick2::TextEdit::effectiveHorizontalAlignment
455 Sets the horizontal and vertical alignment of the text within the TextEdit item's
456 width and height. By default, the text alignment follows the natural alignment
457 of the text, for example text that is read from left to right will be aligned to
460 Valid values for \c horizontalAlignment are:
462 \li TextEdit.AlignLeft (default)
463 \li TextEdit.AlignRight
464 \li TextEdit.AlignHCenter
465 \li TextEdit.AlignJustify
468 Valid values for \c verticalAlignment are:
470 \li TextEdit.AlignTop (default)
471 \li TextEdit.AlignBottom
472 \li TextEdit.AlignVCenter
475 When using the attached property LayoutMirroring::enabled to mirror application
476 layouts, the horizontal alignment of text will also be mirrored. However, the property
477 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
478 of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
480 QQuickTextEdit::HAlignment QQuickTextEdit::hAlign() const
482 Q_D(const QQuickTextEdit);
486 void QQuickTextEdit::setHAlign(HAlignment align)
489 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
490 d->hAlignImplicit = false;
491 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
492 d->updateDefaultTextOption();
497 void QQuickTextEdit::resetHAlign()
500 d->hAlignImplicit = true;
501 if (d->determineHorizontalAlignment() && isComponentComplete()) {
502 d->updateDefaultTextOption();
507 QQuickTextEdit::HAlignment QQuickTextEdit::effectiveHAlign() const
509 Q_D(const QQuickTextEdit);
510 QQuickTextEdit::HAlignment effectiveAlignment = d->hAlign;
511 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
513 case QQuickTextEdit::AlignLeft:
514 effectiveAlignment = QQuickTextEdit::AlignRight;
516 case QQuickTextEdit::AlignRight:
517 effectiveAlignment = QQuickTextEdit::AlignLeft;
523 return effectiveAlignment;
526 bool QQuickTextEditPrivate::setHAlign(QQuickTextEdit::HAlignment alignment, bool forceAlign)
529 if (hAlign != alignment || forceAlign) {
530 QQuickTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
532 emit q->horizontalAlignmentChanged(alignment);
533 if (oldEffectiveHAlign != q->effectiveHAlign())
534 emit q->effectiveHorizontalAlignmentChanged();
541 Qt::LayoutDirection QQuickTextEditPrivate::textDirection(const QString &text) const
543 const QChar *character = text.constData();
544 while (!character->isNull()) {
545 switch (character->direction()) {
547 return Qt::LeftToRight;
551 return Qt::RightToLeft;
557 return Qt::LayoutDirectionAuto;
560 bool QQuickTextEditPrivate::determineHorizontalAlignment()
563 if (hAlignImplicit && q->isComponentComplete()) {
564 Qt::LayoutDirection direction = contentDirection;
565 if (direction == Qt::LayoutDirectionAuto) {
566 const QString preeditText = control->textCursor().block().layout()->preeditAreaText();
567 direction = textDirection(preeditText);
569 if (direction == Qt::LayoutDirectionAuto)
570 direction = qGuiApp->inputMethod()->inputDirection();
572 return setHAlign(direction == Qt::RightToLeft ? QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft);
577 void QQuickTextEditPrivate::mirrorChange()
580 if (q->isComponentComplete()) {
581 if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) {
582 updateDefaultTextOption();
584 emit q->effectiveHorizontalAlignmentChanged();
589 QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const
591 Q_D(const QQuickTextEdit);
595 void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment)
598 if (alignment == d->vAlign)
600 d->vAlign = alignment;
601 d->updateDefaultTextOption();
603 moveCursorDelegate();
604 emit verticalAlignmentChanged(d->vAlign);
607 \qmlproperty enumeration QtQuick2::TextEdit::wrapMode
609 Set this property to wrap the text to the TextEdit item's width.
610 The text will only wrap if an explicit width has been set.
613 \li TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
614 \li TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
615 \li TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
616 \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.
619 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
621 QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode() const
623 Q_D(const QQuickTextEdit);
627 void QQuickTextEdit::setWrapMode(WrapMode mode)
630 if (mode == d->wrapMode)
633 d->updateDefaultTextOption();
635 emit wrapModeChanged();
639 \qmlproperty int QtQuick2::TextEdit::lineCount
641 Returns the total number of lines in the textEdit item.
643 int QQuickTextEdit::lineCount() const
645 Q_D(const QQuickTextEdit);
650 \qmlproperty int QtQuick2::TextEdit::length
652 Returns the total number of plain text characters in the TextEdit item.
654 As this number doesn't include any formatting markup it may not be the same as the
655 length of the string returned by the \l text property.
657 This property can be faster than querying the length the \l text property as it doesn't
658 require any copying or conversion of the TextEdit's internal string data.
661 int QQuickTextEdit::length() const
663 Q_D(const QQuickTextEdit);
664 // QTextDocument::characterCount() includes the terminating null character.
665 return qMax(0, d->document->characterCount() - 1);
669 \qmlproperty real QtQuick2::TextEdit::contentWidth
671 Returns the width of the text, including the width past the width
672 which is covered due to insufficient wrapping if \l wrapMode is set.
674 qreal QQuickTextEdit::contentWidth() const
676 Q_D(const QQuickTextEdit);
677 return d->contentSize.width();
681 \qmlproperty real QtQuick2::TextEdit::contentHeight
683 Returns the height of the text, including the height past the height
684 that is covered if the text does not fit within the set height.
686 qreal QQuickTextEdit::contentHeight() const
688 Q_D(const QQuickTextEdit);
689 return d->contentSize.height();
693 \qmlproperty url QtQuick2::TextEdit::baseUrl
695 This property specifies a base URL which is used to resolve relative URLs
698 By default is the url of the TextEdit element.
701 QUrl QQuickTextEdit::baseUrl() const
703 Q_D(const QQuickTextEdit);
704 if (d->baseUrl.isEmpty()) {
705 if (QQmlContext *context = qmlContext(this))
706 const_cast<QQuickTextEditPrivate *>(d)->baseUrl = context->baseUrl();
711 void QQuickTextEdit::setBaseUrl(const QUrl &url)
714 if (baseUrl() != url) {
717 d->document->setBaseUrl(url, d->richText);
718 emit baseUrlChanged();
722 void QQuickTextEdit::resetBaseUrl()
724 if (QQmlContext *context = qmlContext(this))
725 setBaseUrl(context->baseUrl());
731 \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position)
733 Returns the rectangle at the given \a position in the text. The x, y,
734 and height properties correspond to the cursor that would describe
737 QRectF QQuickTextEdit::positionToRectangle(int pos) const
739 Q_D(const QQuickTextEdit);
740 QTextCursor c(d->document);
742 return d->control->cursorRect(c).translated(0, d->yoff);
747 \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y)
749 Returns the text position closest to pixel position (\a x, \a y).
751 Position 0 is before the first character, position 1 is after the first character
752 but before the second, and so on until position \l {text}.length, which is after all characters.
754 int QQuickTextEdit::positionAt(qreal x, qreal y) const
756 Q_D(const QQuickTextEdit);
757 int r = d->document->documentLayout()->hitTest(QPointF(x,y-d->yoff), Qt::FuzzyHit);
758 QTextCursor cursor = d->control->textCursor();
759 if (r > cursor.position()) {
760 // The cursor position includes positions within the preedit text, but only positions in the
761 // same text block are offset so it is possible to get a position that is either part of the
762 // preedit or the next text block.
763 QTextLayout *layout = cursor.block().layout();
764 const int preeditLength = layout
765 ? layout->preeditAreaText().length()
767 if (preeditLength > 0
768 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
769 r = r > cursor.position() + preeditLength
778 \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
780 Moves the cursor to \a position and updates the selection according to the optional \a mode
781 parameter. (To only move the cursor, set the \l cursorPosition property.)
783 When this method is called it additionally sets either the
784 selectionStart or the selectionEnd (whichever was at the previous cursor position)
785 to the specified position. This allows you to easily extend and contract the selected
788 The selection mode specifies whether the selection is updated on a per character or a per word
789 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
792 \li TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
793 the previous cursor position) to the specified position.
794 \li TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
795 words between the specified position and the previous cursor position. Words partially in the
799 For example, take this sequence of calls:
803 moveCursorSelection(9, TextEdit.SelectCharacters)
804 moveCursorSelection(7, TextEdit.SelectCharacters)
807 This moves the cursor to position 5, extend the selection end from 5 to 9
808 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
809 selected (the 6th and 7th characters).
811 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
812 before or on position 5 and extend the selection end to a word boundary on or past position 9.
814 void QQuickTextEdit::moveCursorSelection(int pos)
816 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
818 QTextCursor cursor = d->control->textCursor();
819 if (cursor.position() == pos)
821 cursor.setPosition(pos, QTextCursor::KeepAnchor);
822 d->control->setTextCursor(cursor);
825 void QQuickTextEdit::moveCursorSelection(int pos, SelectionMode mode)
828 QTextCursor cursor = d->control->textCursor();
829 if (cursor.position() == pos)
831 if (mode == SelectCharacters) {
832 cursor.setPosition(pos, QTextCursor::KeepAnchor);
833 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
834 if (cursor.anchor() > cursor.position()) {
835 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
836 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
837 if (cursor.position() == cursor.anchor())
838 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
840 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
842 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
843 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
846 cursor.setPosition(pos, QTextCursor::KeepAnchor);
847 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
848 if (cursor.position() != pos)
849 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
850 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
851 if (cursor.anchor() < cursor.position()) {
852 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
853 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
855 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
856 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
857 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
858 if (cursor.position() != cursor.anchor()) {
859 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
860 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
864 cursor.setPosition(pos, QTextCursor::KeepAnchor);
865 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
866 if (cursor.position() != pos) {
867 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
868 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
871 d->control->setTextCursor(cursor);
875 \qmlproperty bool QtQuick2::TextEdit::cursorVisible
876 If true the text edit shows a cursor.
878 This property is set and unset when the text edit gets active focus, but it can also
879 be set directly (useful, for example, if a KeyProxy might forward keys to it).
881 bool QQuickTextEdit::isCursorVisible() const
883 Q_D(const QQuickTextEdit);
884 return d->cursorVisible;
887 void QQuickTextEdit::setCursorVisible(bool on)
890 if (d->cursorVisible == on)
892 d->cursorVisible = on;
893 if (!on && !d->persistentSelection)
894 d->control->setCursorIsFocusIndicator(true);
895 d->control->setCursorVisible(on);
896 emit cursorVisibleChanged(d->cursorVisible);
900 \qmlproperty int QtQuick2::TextEdit::cursorPosition
901 The position of the cursor in the TextEdit.
903 int QQuickTextEdit::cursorPosition() const
905 Q_D(const QQuickTextEdit);
906 return d->control->textCursor().position();
909 void QQuickTextEdit::setCursorPosition(int pos)
912 if (pos < 0 || pos >= d->document->characterCount()) // characterCount includes the terminating null.
914 QTextCursor cursor = d->control->textCursor();
915 if (cursor.position() == pos && cursor.anchor() == pos)
917 cursor.setPosition(pos);
918 d->control->setTextCursor(cursor);
919 d->control->updateCursorRectangle(true);
923 \qmlproperty Component QtQuick2::TextEdit::cursorDelegate
924 The delegate for the cursor in the TextEdit.
926 If you set a cursorDelegate for a TextEdit, this delegate will be used for
927 drawing the cursor instead of the standard cursor. An instance of the
928 delegate will be created and managed by the text edit when a cursor is
929 needed, and the x and y properties of delegate instance will be set so as
930 to be one pixel before the top left of the current character.
932 Note that the root item of the delegate component must be a QQuickItem or
933 QQuickItem derived item.
935 QQmlComponent* QQuickTextEdit::cursorDelegate() const
937 Q_D(const QQuickTextEdit);
938 return d->cursorComponent;
941 void QQuickTextEdit::setCursorDelegate(QQmlComponent* c)
944 if (d->cursorComponent) {
946 d->control->setCursorWidth(-1);
952 d->cursorComponent = c;
953 if (c && c->isReady()) {
954 loadCursorDelegate();
957 connect(c, SIGNAL(statusChanged()),
958 this, SLOT(loadCursorDelegate()));
961 emit cursorDelegateChanged();
964 void QQuickTextEdit::loadCursorDelegate()
967 if (d->cursorComponent->isLoading() || !isComponentComplete())
969 QQmlContext *creationContext = d->cursorComponent->creationContext();
970 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
971 d->cursor = qobject_cast<QQuickItem*>(object);
973 d->control->setCursorWidth(0);
975 QQml_setParent_noEvent(d->cursor, this);
976 d->cursor->setParentItem(this);
977 d->cursor->setHeight(QFontMetrics(d->font).height());
978 moveCursorDelegate();
981 qmlInfo(this) << "Error loading cursor delegate.";
986 \qmlproperty int QtQuick2::TextEdit::selectionStart
988 The cursor position before the first character in the current selection.
990 This property is read-only. To change the selection, use select(start,end),
991 selectAll(), or selectWord().
993 \sa selectionEnd, cursorPosition, selectedText
995 int QQuickTextEdit::selectionStart() const
997 Q_D(const QQuickTextEdit);
998 return d->control->textCursor().selectionStart();
1002 \qmlproperty int QtQuick2::TextEdit::selectionEnd
1004 The cursor position after the last character in the current selection.
1006 This property is read-only. To change the selection, use select(start,end),
1007 selectAll(), or selectWord().
1009 \sa selectionStart, cursorPosition, selectedText
1011 int QQuickTextEdit::selectionEnd() const
1013 Q_D(const QQuickTextEdit);
1014 return d->control->textCursor().selectionEnd();
1018 \qmlproperty string QtQuick2::TextEdit::selectedText
1020 This read-only property provides the text currently selected in the
1023 It is equivalent to the following snippet, but is faster and easier
1026 //myTextEdit is the id of the TextEdit
1027 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
1028 myTextEdit.selectionEnd);
1031 QString QQuickTextEdit::selectedText() const
1033 Q_D(const QQuickTextEdit);
1034 return d->control->textCursor().selectedText();
1038 \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress
1040 Whether the TextEdit should gain active focus on a mouse press. By default this is
1043 bool QQuickTextEdit::focusOnPress() const
1045 Q_D(const QQuickTextEdit);
1046 return d->focusOnPress;
1049 void QQuickTextEdit::setFocusOnPress(bool on)
1051 Q_D(QQuickTextEdit);
1052 if (d->focusOnPress == on)
1054 d->focusOnPress = on;
1055 emit activeFocusOnPressChanged(d->focusOnPress);
1059 \qmlproperty bool QtQuick2::TextEdit::persistentSelection
1061 Whether the TextEdit should keep the selection visible when it loses active focus to another
1062 item in the scene. By default this is set to true;
1064 bool QQuickTextEdit::persistentSelection() const
1066 Q_D(const QQuickTextEdit);
1067 return d->persistentSelection;
1070 void QQuickTextEdit::setPersistentSelection(bool on)
1072 Q_D(QQuickTextEdit);
1073 if (d->persistentSelection == on)
1075 d->persistentSelection = on;
1076 emit persistentSelectionChanged(d->persistentSelection);
1080 \qmlproperty real QtQuick2::TextEdit::textMargin
1082 The margin, in pixels, around the text in the TextEdit.
1084 qreal QQuickTextEdit::textMargin() const
1086 Q_D(const QQuickTextEdit);
1087 return d->textMargin;
1090 void QQuickTextEdit::setTextMargin(qreal margin)
1092 Q_D(QQuickTextEdit);
1093 if (d->textMargin == margin)
1095 d->textMargin = margin;
1096 d->document->setDocumentMargin(d->textMargin);
1097 emit textMarginChanged(d->textMargin);
1101 \qmlproperty enumeration QtQuick2::TextEdit::inputMethodHints
1103 Provides hints to the input method about the expected content of the text edit and how it
1106 The value is a bit-wise combination of flags or Qt.ImhNone if no hints are set.
1108 Flags that alter behaviour are:
1111 \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1112 \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1113 in any persistent storage like predictive user dictionary.
1114 \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1115 when a sentence ends.
1116 \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1117 \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1118 \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1119 \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1121 \li Qt.ImhDate - The text editor functions as a date field.
1122 \li Qt.ImhTime - The text editor functions as a time field.
1125 Flags that restrict input (exclusive flags) are:
1128 \li Qt.ImhDigitsOnly - Only digits are allowed.
1129 \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1130 \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1131 \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1132 \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1133 \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1134 \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1140 \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1144 Qt::InputMethodHints QQuickTextEdit::inputMethodHints() const
1146 Q_D(const QQuickTextEdit);
1147 return d->inputMethodHints;
1150 void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints)
1152 Q_D(QQuickTextEdit);
1154 if (hints == d->inputMethodHints)
1157 d->inputMethodHints = hints;
1158 updateInputMethod(Qt::ImHints);
1159 emit inputMethodHintsChanged();
1162 void QQuickTextEdit::geometryChanged(const QRectF &newGeometry,
1163 const QRectF &oldGeometry)
1165 Q_D(QQuickTextEdit);
1166 if (newGeometry.width() != oldGeometry.width() && widthValid() && !d->inLayout) {
1168 moveCursorDelegate();
1170 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1175 Ensures any delayed caching or data loading the class
1176 needs to performed is complete.
1178 void QQuickTextEdit::componentComplete()
1180 Q_D(QQuickTextEdit);
1181 QQuickImplicitSizeItem::componentComplete();
1183 d->document->setBaseUrl(baseUrl(), d->richText);
1185 d->determineHorizontalAlignment();
1186 d->updateDefaultTextOption();
1190 if (d->cursorComponent && d->cursorComponent->isReady())
1191 loadCursorDelegate();
1194 \qmlproperty bool QtQuick2::TextEdit::selectByMouse
1198 If true, the user can use the mouse to select text in some
1199 platform-specific way. Note that for some platforms this may
1200 not be an appropriate interaction (eg. may conflict with how
1201 the text needs to behave inside a Flickable.
1203 bool QQuickTextEdit::selectByMouse() const
1205 Q_D(const QQuickTextEdit);
1206 return d->selectByMouse;
1209 void QQuickTextEdit::setSelectByMouse(bool on)
1211 Q_D(QQuickTextEdit);
1212 if (d->selectByMouse != on) {
1213 d->selectByMouse = on;
1214 setKeepMouseGrab(on);
1216 setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1218 setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1219 emit selectByMouseChanged(on);
1224 \qmlproperty enum QtQuick2::TextEdit::mouseSelectionMode
1226 Specifies how text should be selected using a mouse.
1229 \li TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1230 \li TextEdit.SelectWords - The selection is updated with whole words.
1233 This property only applies when \l selectByMouse is true.
1235 QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode() const
1237 Q_D(const QQuickTextEdit);
1238 return d->mouseSelectionMode;
1241 void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode)
1243 Q_D(QQuickTextEdit);
1244 if (d->mouseSelectionMode != mode) {
1245 d->mouseSelectionMode = mode;
1246 d->control->setWordSelectionEnabled(mode == SelectWords);
1247 emit mouseSelectionModeChanged(mode);
1252 \qmlproperty bool QtQuick2::TextEdit::readOnly
1254 Whether the user can interact with the TextEdit item. If this
1255 property is set to true the text cannot be edited by user interaction.
1257 By default this property is false.
1259 void QQuickTextEdit::setReadOnly(bool r)
1261 Q_D(QQuickTextEdit);
1262 if (r == isReadOnly())
1265 setFlag(QQuickItem::ItemAcceptsInputMethod, !r);
1266 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1267 if (d->selectByMouse)
1268 flags = flags | Qt::TextSelectableByMouse;
1270 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1271 d->control->setTextInteractionFlags(flags);
1273 d->control->moveCursor(QTextCursor::End);
1275 updateInputMethod(Qt::ImEnabled);
1276 q_canPasteChanged();
1277 emit readOnlyChanged(r);
1280 bool QQuickTextEdit::isReadOnly() const
1282 Q_D(const QQuickTextEdit);
1283 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1287 Sets how the text edit should interact with user input to the given
1290 void QQuickTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1292 Q_D(QQuickTextEdit);
1293 d->control->setTextInteractionFlags(flags);
1297 Returns the flags specifying how the text edit should interact
1300 Qt::TextInteractionFlags QQuickTextEdit::textInteractionFlags() const
1302 Q_D(const QQuickTextEdit);
1303 return d->control->textInteractionFlags();
1307 \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle
1309 The rectangle where the standard text cursor is rendered
1310 within the text edit. Read-only.
1312 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
1313 automatically when it changes. The width of the delegate is unaffected by changes in the
1316 QRectF QQuickTextEdit::cursorRectangle() const
1318 Q_D(const QQuickTextEdit);
1319 return d->control->cursorRect().translated(0, d->yoff);
1322 bool QQuickTextEdit::event(QEvent *event)
1324 Q_D(QQuickTextEdit);
1325 if (event->type() == QEvent::ShortcutOverride) {
1326 d->control->processEvent(event, QPointF(0, -d->yoff));
1327 return event->isAccepted();
1329 return QQuickImplicitSizeItem::event(event);
1334 Handles the given key \a event.
1336 void QQuickTextEdit::keyPressEvent(QKeyEvent *event)
1338 Q_D(QQuickTextEdit);
1339 d->control->processEvent(event, QPointF(0, -d->yoff));
1340 if (!event->isAccepted())
1341 QQuickImplicitSizeItem::keyPressEvent(event);
1346 Handles the given key \a event.
1348 void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event)
1350 Q_D(QQuickTextEdit);
1351 d->control->processEvent(event, QPointF(0, -d->yoff));
1352 if (!event->isAccepted())
1353 QQuickImplicitSizeItem::keyReleaseEvent(event);
1357 \qmlmethod void QtQuick2::TextEdit::deselect()
1359 Removes active text selection.
1361 void QQuickTextEdit::deselect()
1363 Q_D(QQuickTextEdit);
1364 QTextCursor c = d->control->textCursor();
1366 d->control->setTextCursor(c);
1370 \qmlmethod void QtQuick2::TextEdit::selectAll()
1372 Causes all text to be selected.
1374 void QQuickTextEdit::selectAll()
1376 Q_D(QQuickTextEdit);
1377 d->control->selectAll();
1381 \qmlmethod void QtQuick2::TextEdit::selectWord()
1383 Causes the word closest to the current cursor position to be selected.
1385 void QQuickTextEdit::selectWord()
1387 Q_D(QQuickTextEdit);
1388 QTextCursor c = d->control->textCursor();
1389 c.select(QTextCursor::WordUnderCursor);
1390 d->control->setTextCursor(c);
1394 \qmlmethod void QtQuick2::TextEdit::select(int start, int end)
1396 Causes the text from \a start to \a end to be selected.
1398 If either start or end is out of range, the selection is not changed.
1400 After calling this, selectionStart will become the lesser
1401 and selectionEnd will become the greater (regardless of the order passed
1404 \sa selectionStart, selectionEnd
1406 void QQuickTextEdit::select(int start, int end)
1408 Q_D(QQuickTextEdit);
1409 if (start < 0 || end < 0 || start >= d->document->characterCount() || end >= d->document->characterCount())
1411 QTextCursor cursor = d->control->textCursor();
1412 cursor.beginEditBlock();
1413 cursor.setPosition(start, QTextCursor::MoveAnchor);
1414 cursor.setPosition(end, QTextCursor::KeepAnchor);
1415 cursor.endEditBlock();
1416 d->control->setTextCursor(cursor);
1419 updateSelectionMarkers();
1423 \qmlmethod void QtQuick2::TextEdit::isRightToLeft(int start, int end)
1425 Returns true if the natural reading direction of the editor text
1426 found between positions \a start and \a end is right to left.
1428 bool QQuickTextEdit::isRightToLeft(int start, int end)
1431 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1434 return getText(start, end).isRightToLeft();
1438 #ifndef QT_NO_CLIPBOARD
1440 \qmlmethod QtQuick2::TextEdit::cut()
1442 Moves the currently selected text to the system clipboard.
1444 void QQuickTextEdit::cut()
1446 Q_D(QQuickTextEdit);
1451 \qmlmethod QtQuick2::TextEdit::copy()
1453 Copies the currently selected text to the system clipboard.
1455 void QQuickTextEdit::copy()
1457 Q_D(QQuickTextEdit);
1462 \qmlmethod QtQuick2::TextEdit::paste()
1464 Replaces the currently selected text by the contents of the system clipboard.
1466 void QQuickTextEdit::paste()
1468 Q_D(QQuickTextEdit);
1469 d->control->paste();
1471 #endif // QT_NO_CLIPBOARD
1475 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1476 current selection, and updates the selection start to the current cursor
1480 void QQuickTextEdit::undo()
1482 Q_D(QQuickTextEdit);
1487 Redoes the last operation if redo is \l {canRedo}{available}.
1490 void QQuickTextEdit::redo()
1492 Q_D(QQuickTextEdit);
1498 Handles the given mouse \a event.
1500 void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
1502 Q_D(QQuickTextEdit);
1503 d->control->processEvent(event, QPointF(0, -d->yoff));
1504 if (d->focusOnPress){
1505 bool hadActiveFocus = hasActiveFocus();
1507 // re-open input panel on press if already focused
1508 if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
1509 openSoftwareInputPanel();
1511 if (!event->isAccepted())
1512 QQuickImplicitSizeItem::mousePressEvent(event);
1517 Handles the given mouse \a event.
1519 void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
1521 Q_D(QQuickTextEdit);
1522 d->control->processEvent(event, QPointF(0, -d->yoff));
1524 if (!event->isAccepted())
1525 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1530 Handles the given mouse \a event.
1532 void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
1534 Q_D(QQuickTextEdit);
1535 d->control->processEvent(event, QPointF(0, -d->yoff));
1536 if (!event->isAccepted())
1537 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1542 Handles the given mouse \a event.
1544 void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
1546 Q_D(QQuickTextEdit);
1547 d->control->processEvent(event, QPointF(0, -d->yoff));
1548 if (!event->isAccepted())
1549 QQuickImplicitSizeItem::mouseMoveEvent(event);
1554 Handles the given input method \a event.
1556 void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
1558 Q_D(QQuickTextEdit);
1559 const bool wasComposing = isInputMethodComposing();
1560 d->control->processEvent(event, QPointF(0, -d->yoff));
1561 setCursorVisible(d->control->cursorVisible());
1562 if (wasComposing != isInputMethodComposing())
1563 emit inputMethodComposingChanged();
1566 void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1568 Q_D(QQuickTextEdit);
1569 if (change == ItemActiveFocusHasChanged) {
1570 setCursorVisible(value.boolValue); // ### refactor: focus handling && d->canvas && d->canvas->hasFocus());
1571 QFocusEvent focusEvent(value.boolValue ? QEvent::FocusIn : QEvent::FocusOut);
1572 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
1573 if (value.boolValue) {
1574 q_updateAlignment();
1575 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1576 this, SLOT(q_updateAlignment()));
1578 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1579 this, SLOT(q_updateAlignment()));
1582 QQuickItem::itemChange(change, value);
1587 Returns the value of the given \a property.
1589 QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1591 Q_D(const QQuickTextEdit);
1596 v = (bool)(flags() & ItemAcceptsInputMethod);
1599 v = (int)inputMethodHints();
1602 v = d->control->inputMethodQuery(property);
1609 void QQuickTextEdit::triggerPreprocess()
1611 Q_D(QQuickTextEdit);
1612 if (d->updateType == QQuickTextEditPrivate::UpdateNone)
1613 d->updateType = QQuickTextEditPrivate::UpdateOnlyPreprocess;
1617 QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1619 Q_UNUSED(updatePaintNodeData);
1620 Q_D(QQuickTextEdit);
1622 if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode && oldNode != 0) {
1623 // Update done in preprocess() in the nodes
1624 d->updateType = QQuickTextEditPrivate::UpdateNone;
1628 d->updateType = QQuickTextEditPrivate::UpdateNone;
1630 QSGNode *currentNode = oldNode;
1631 if (oldNode == 0 || d->documentDirty) {
1632 d->documentDirty = false;
1634 #if defined(Q_OS_MAC)
1635 // Make sure document is relayouted in the paint node on Mac
1636 // to avoid crashes due to the font engines created in the
1638 d->document->markContentsDirty(0, d->document->characterCount());
1641 QQuickTextNode *node = 0;
1643 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1646 node = static_cast<QQuickTextNode *>(oldNode);
1649 node->deleteContent();
1650 node->setMatrix(QMatrix4x4());
1652 QRectF bounds = boundingRect();
1654 node->addTextDocument(bounds.topLeft(), d->document, d->color, QQuickText::Normal, QColor(),
1655 QColor(), d->selectionColor, d->selectedTextColor, selectionStart(),
1656 selectionEnd() - 1); // selectionEnd() returns first char after
1659 #if defined(Q_OS_MAC)
1660 // We also need to make sure the document layout is redone when
1661 // control is returned to the main thread, as all the font engines
1662 // are now owned by the rendering thread
1663 d->document->markContentsDirty(0, d->document->characterCount());
1667 if (d->cursorComponent == 0 && !isReadOnly()) {
1668 QQuickTextNode *node = static_cast<QQuickTextNode *>(currentNode);
1670 QColor color = (!d->cursorVisible || !d->control->cursorOn())
1671 ? QColor(0, 0, 0, 0)
1674 if (node->cursorNode() == 0) {
1675 node->setCursor(cursorRectangle(), color);
1677 node->cursorNode()->setRect(cursorRectangle());
1678 node->cursorNode()->setColor(color);
1687 \qmlproperty bool QtQuick2::TextEdit::smooth
1689 This property holds whether the text is smoothly scaled or transformed.
1691 Smooth filtering gives better visual quality, but is slower. If
1692 the item is displayed at its natural size, this property has no visual or
1695 \note Generally scaling artifacts are only visible if the item is stationary on
1696 the screen. A common pattern when animating an item is to disable smooth
1697 filtering at the beginning of the animation and reenable it at the conclusion.
1701 \qmlproperty bool QtQuick2::TextEdit::canPaste
1703 Returns true if the TextEdit is writable and the content of the clipboard is
1704 suitable for pasting into the TextEdit.
1706 bool QQuickTextEdit::canPaste() const
1708 Q_D(const QQuickTextEdit);
1709 if (!d->canPasteValid) {
1710 const_cast<QQuickTextEditPrivate *>(d)->canPaste = d->control->canPaste();
1711 const_cast<QQuickTextEditPrivate *>(d)->canPasteValid = true;
1717 \qmlproperty bool QtQuick2::TextEdit::canUndo
1719 Returns true if the TextEdit is writable and there are previous operations
1723 bool QQuickTextEdit::canUndo() const
1725 Q_D(const QQuickTextEdit);
1726 return d->document->isUndoAvailable();
1730 \qmlproperty bool QtQuick2::TextEdit::canRedo
1732 Returns true if the TextEdit is writable and there are \l {undo}{undone}
1733 operations that can be redone.
1736 bool QQuickTextEdit::canRedo() const
1738 Q_D(const QQuickTextEdit);
1739 return d->document->isRedoAvailable();
1743 \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1746 This property holds whether the TextEdit has partial text input from an
1749 While it is composing an input method may rely on mouse or key events from
1750 the TextEdit to edit or commit the partial text. This property can be used
1751 to determine when to disable events handlers that may interfere with the
1752 correct operation of an input method.
1754 bool QQuickTextEdit::isInputMethodComposing() const
1756 Q_D(const QQuickTextEdit);
1757 return d->control->hasImState();
1760 void QQuickTextEditPrivate::init()
1762 Q_Q(QQuickTextEdit);
1764 q->setSmooth(smooth);
1765 q->setAcceptedMouseButtons(Qt::LeftButton);
1766 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1767 q->setFlag(QQuickItem::ItemHasContents);
1769 document = new QQuickTextDocumentWithImageResources(q);
1771 control = new QQuickTextControl(document, q);
1772 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1773 control->setAcceptRichText(false);
1774 control->setCursorIsFocusIndicator(true);
1776 FAST_CONNECT(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateDocument()));
1777 FAST_CONNECT(control, SIGNAL(updateCursorRequest()), q, SLOT(updateCursor()));
1778 FAST_CONNECT(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1779 FAST_CONNECT(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1780 FAST_CONNECT(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1781 FAST_CONNECT(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1782 FAST_CONNECT(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1783 FAST_CONNECT(control, SIGNAL(cursorRectangleChanged()), q, SLOT(moveCursorDelegate()));
1784 FAST_CONNECT(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1785 #ifndef QT_NO_CLIPBOARD
1786 FAST_CONNECT(QGuiApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1788 FAST_CONNECT(document, SIGNAL(undoAvailable(bool)), q, SIGNAL(canUndoChanged()));
1789 FAST_CONNECT(document, SIGNAL(redoAvailable(bool)), q, SIGNAL(canRedoChanged()));
1790 FAST_CONNECT(document, SIGNAL(imagesLoaded()), q, SLOT(updateSize()));
1792 document->setDefaultFont(font);
1793 document->setDocumentMargin(textMargin);
1794 document->setUndoRedoEnabled(false); // flush undo buffer.
1795 document->setUndoRedoEnabled(true);
1796 updateDefaultTextOption();
1799 void QQuickTextEdit::q_textChanged()
1801 Q_D(QQuickTextEdit);
1802 d->textCached = false;
1803 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1804 d->contentDirection = d->textDirection(it.text());
1805 if (d->contentDirection != Qt::LayoutDirectionAuto)
1808 d->determineHorizontalAlignment();
1809 d->updateDefaultTextOption();
1815 void QQuickTextEdit::moveCursorDelegate()
1817 Q_D(QQuickTextEdit);
1818 d->determineHorizontalAlignment();
1819 updateInputMethod();
1820 emit cursorRectangleChanged();
1823 QRectF cursorRect = cursorRectangle();
1824 d->cursor->setX(cursorRect.x());
1825 d->cursor->setY(cursorRect.y());
1828 void QQuickTextEdit::updateSelectionMarkers()
1830 Q_D(QQuickTextEdit);
1831 if (d->lastSelectionStart != d->control->textCursor().selectionStart()) {
1832 d->lastSelectionStart = d->control->textCursor().selectionStart();
1833 emit selectionStartChanged();
1835 if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) {
1836 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1837 emit selectionEndChanged();
1841 QRectF QQuickTextEdit::boundingRect() const
1843 Q_D(const QQuickTextEdit);
1844 QRectF r(0, -d->yoff, d->contentSize.width(), d->contentSize.height());
1845 int cursorWidth = 1;
1848 else if (!d->document->isEmpty())
1849 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1851 // Could include font max left/right bearings to either side of rectangle.
1853 r.setRight(r.right() + cursorWidth);
1856 switch (d->vAlign) {
1860 r.moveTop(h - r.height());
1863 r.moveTop((h - r.height()) / 2);
1868 switch (d->hAlign) {
1873 r.moveLeft(w - r.width());
1876 r.moveLeft((w - r.width()) / 2);
1883 QRectF QQuickTextEdit::clipRect() const
1885 Q_D(const QQuickTextEdit);
1886 QRectF r = QQuickImplicitSizeItem::clipRect();
1887 int cursorWidth = 1;
1889 cursorWidth = d->cursor->width();
1890 if (!d->document->isEmpty())
1891 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1893 // Could include font max left/right bearings to either side of rectangle.
1895 r.setRight(r.right() + cursorWidth);
1899 qreal QQuickTextEditPrivate::getImplicitWidth() const
1901 Q_Q(const QQuickTextEdit);
1902 if (!requireImplicitWidth) {
1903 // We don't calculate implicitWidth unless it is required.
1904 // We need to force a size update now to ensure implicitWidth is calculated
1905 const_cast<QQuickTextEditPrivate*>(this)->requireImplicitWidth = true;
1906 const_cast<QQuickTextEdit*>(q)->updateSize();
1908 return implicitWidth;
1911 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1912 // need to do all the calculations each time
1913 void QQuickTextEdit::updateSize()
1915 Q_D(QQuickTextEdit);
1916 if (isComponentComplete()) {
1917 qreal naturalWidth = d->implicitWidth;
1918 // ### assumes that if the width is set, the text will fill to edges
1919 // ### (unless wrap is false, then clipping will occur)
1921 if (!d->requireImplicitWidth) {
1922 emit implicitWidthChanged();
1923 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1924 if (d->requireImplicitWidth)
1927 if (d->requireImplicitWidth) {
1928 d->document->setTextWidth(-1);
1929 naturalWidth = d->document->idealWidth();
1931 const bool wasInLayout = d->inLayout;
1933 setImplicitWidth(naturalWidth);
1934 d->inLayout = wasInLayout;
1935 if (d->inLayout) // probably the result of a binding loop, but by letting it
1936 return; // get this far we'll get a warning to that effect.
1938 if (d->document->textWidth() != width())
1939 d->document->setTextWidth(width());
1941 d->document->setTextWidth(-1);
1943 QFontMetricsF fm(d->font);
1944 qreal dy = height();
1945 dy -= d->document->size().height();
1948 if (heightValid()) {
1949 if (d->vAlign == AlignBottom)
1951 else if (d->vAlign == AlignVCenter)
1958 if (nyoff != d->yoff)
1960 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1962 //### need to comfirm cost of always setting these
1963 qreal newWidth = d->document->idealWidth();
1964 if (!widthValid() && d->document->textWidth() != newWidth)
1965 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1966 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1968 if (!widthValid() && !d->requireImplicitWidth)
1971 qreal newHeight = d->document->isEmpty() ? qCeil(fm.height()) : d->document->size().height();
1974 setImplicitSize(iWidth, newHeight);
1976 setImplicitHeight(newHeight);
1978 QSizeF size(newWidth, newHeight);
1979 if (d->contentSize != size) {
1980 d->contentSize = size;
1981 emit contentSizeChanged();
1989 void QQuickTextEdit::updateDocument()
1991 Q_D(QQuickTextEdit);
1992 d->documentDirty = true;
1994 if (isComponentComplete()) {
1995 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
2000 void QQuickTextEdit::updateCursor()
2002 Q_D(QQuickTextEdit);
2003 if (isComponentComplete()) {
2004 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
2009 void QQuickTextEdit::q_updateAlignment()
2011 Q_D(QQuickTextEdit);
2012 if (d->determineHorizontalAlignment()) {
2013 d->updateDefaultTextOption();
2014 moveCursorDelegate();
2018 void QQuickTextEdit::updateTotalLines()
2020 Q_D(QQuickTextEdit);
2024 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
2025 QTextLayout *layout = it.layout();
2028 subLines += layout->lineCount()-1;
2031 int newTotalLines = d->document->lineCount() + subLines;
2032 if (d->lineCount != newTotalLines) {
2033 d->lineCount = newTotalLines;
2034 emit lineCountChanged();
2038 void QQuickTextEditPrivate::updateDefaultTextOption()
2040 Q_Q(QQuickTextEdit);
2041 QTextOption opt = document->defaultTextOption();
2042 int oldAlignment = opt.alignment();
2043 Qt::LayoutDirection oldTextDirection = opt.textDirection();
2045 QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
2046 if (contentDirection == Qt::RightToLeft) {
2047 if (horizontalAlignment == QQuickTextEdit::AlignLeft)
2048 horizontalAlignment = QQuickTextEdit::AlignRight;
2049 else if (horizontalAlignment == QQuickTextEdit::AlignRight)
2050 horizontalAlignment = QQuickTextEdit::AlignLeft;
2052 if (!hAlignImplicit)
2053 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
2055 opt.setAlignment(Qt::Alignment(vAlign));
2057 if (contentDirection == Qt::LayoutDirectionAuto) {
2058 opt.setTextDirection(qGuiApp->inputMethod()->inputDirection());
2060 opt.setTextDirection(contentDirection);
2063 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
2064 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
2065 opt.setUseDesignMetrics(true);
2067 if (oldWrapMode != opt.wrapMode() || oldAlignment != opt.alignment()
2068 || oldTextDirection != opt.textDirection()) {
2069 document->setDefaultTextOption(opt);
2076 \qmlmethod void QtQuick2::TextEdit::openSoftwareInputPanel()
2078 Opens software input panels like virtual keyboards for typing, useful for
2079 customizing when you want the input keyboard to be shown and hidden in
2082 By default the opening of input panels follows the platform style. Input panels are
2083 always closed if no editor has active focus.
2085 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2086 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2087 the behavior you want.
2089 Only relevant on platforms, which provide virtual keyboards.
2095 text: "Hello world!"
2096 activeFocusOnPress: false
2098 anchors.fill: parent
2100 if (!textEdit.activeFocus) {
2101 textEdit.forceActiveFocus();
2102 textEdit.openSoftwareInputPanel();
2104 textEdit.focus = false;
2107 onPressAndHold: textEdit.closeSoftwareInputPanel();
2112 void QQuickTextEdit::openSoftwareInputPanel()
2115 qGuiApp->inputMethod()->show();
2119 \qmlmethod void QtQuick2::TextEdit::closeSoftwareInputPanel()
2121 Closes a software input panel like a virtual keyboard shown on the screen, useful
2122 for customizing when you want the input keyboard to be shown and hidden in
2125 By default the opening of input panels follows the platform style. Input panels are
2126 always closed if no editor has active focus.
2128 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2129 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2130 the behavior you want.
2132 Only relevant on platforms, which provide virtual keyboards.
2138 text: "Hello world!"
2139 activeFocusOnPress: false
2141 anchors.fill: parent
2143 if (!textEdit.activeFocus) {
2144 textEdit.forceActiveFocus();
2145 textEdit.openSoftwareInputPanel();
2147 textEdit.focus = false;
2150 onPressAndHold: textEdit.closeSoftwareInputPanel();
2155 void QQuickTextEdit::closeSoftwareInputPanel()
2158 qGuiApp->inputMethod()->hide();
2161 void QQuickTextEdit::focusInEvent(QFocusEvent *event)
2163 Q_D(const QQuickTextEdit);
2164 if (d->focusOnPress && !isReadOnly())
2165 openSoftwareInputPanel();
2166 QQuickImplicitSizeItem::focusInEvent(event);
2169 void QQuickTextEdit::q_canPasteChanged()
2171 Q_D(QQuickTextEdit);
2172 bool old = d->canPaste;
2173 d->canPaste = d->control->canPaste();
2174 bool changed = old!=d->canPaste || !d->canPasteValid;
2175 d->canPasteValid = true;
2177 emit canPasteChanged();
2181 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2183 Returns the section of text that is between the \a start and \a end positions.
2185 The returned text does not include any rich text formatting.
2188 QString QQuickTextEdit::getText(int start, int end) const
2190 Q_D(const QQuickTextEdit);
2191 start = qBound(0, start, d->document->characterCount() - 1);
2192 end = qBound(0, end, d->document->characterCount() - 1);
2193 QTextCursor cursor(d->document);
2194 cursor.setPosition(start, QTextCursor::MoveAnchor);
2195 cursor.setPosition(end, QTextCursor::KeepAnchor);
2196 return cursor.selectedText();
2200 \qmlmethod string QtQuick2::TextEdit::getFormattedText(int start, int end)
2202 Returns the section of text that is between the \a start and \a end positions.
2204 The returned text will be formatted according the \l textFormat property.
2207 QString QQuickTextEdit::getFormattedText(int start, int end) const
2209 Q_D(const QQuickTextEdit);
2211 start = qBound(0, start, d->document->characterCount() - 1);
2212 end = qBound(0, end, d->document->characterCount() - 1);
2214 QTextCursor cursor(d->document);
2215 cursor.setPosition(start, QTextCursor::MoveAnchor);
2216 cursor.setPosition(end, QTextCursor::KeepAnchor);
2219 #ifndef QT_NO_TEXTHTMLPARSER
2220 return cursor.selection().toHtml();
2222 return cursor.selection().toPlainText();
2225 return cursor.selection().toPlainText();
2230 \qmlmethod void QtQuick2::TextEdit::insert(int position, string text)
2232 Inserts \a text into the TextEdit at position.
2234 void QQuickTextEdit::insert(int position, const QString &text)
2236 Q_D(QQuickTextEdit);
2237 if (position < 0 || position >= d->document->characterCount())
2239 QTextCursor cursor(d->document);
2240 cursor.setPosition(position);
2241 d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text));
2243 #ifndef QT_NO_TEXTHTMLPARSER
2244 cursor.insertHtml(text);
2246 cursor.insertText(text);
2249 cursor.insertText(text);
2251 d->control->updateCursorRectangle(false);
2255 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2257 Removes the section of text that is between the \a start and \a end positions from the TextEdit.
2260 void QQuickTextEdit::remove(int start, int end)
2262 Q_D(QQuickTextEdit);
2263 start = qBound(0, start, d->document->characterCount() - 1);
2264 end = qBound(0, end, d->document->characterCount() - 1);
2265 QTextCursor cursor(d->document);
2266 cursor.setPosition(start, QTextCursor::MoveAnchor);
2267 cursor.setPosition(end, QTextCursor::KeepAnchor);
2268 cursor.removeSelectedText();
2269 d->control->updateCursorRectangle(false);