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 QtDeclarative 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 <QtDeclarative/qdeclarativeinfo.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/qdeclarativeglobal_p.h>
59 #include <private/qdeclarativeproperty_p.h>
60 #include <private/qtextengine_p.h>
61 #include <QtQuick/private/qsgtexture_p.h>
62 #include <private/qsgadaptationlayer_p.h>
66 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
67 DEFINE_BOOL_CONFIG_OPTION(qmlEnableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE)
70 \qmlclass TextEdit QQuickTextEdit
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextEdit item displays multiple lines of editable formatted text.
76 The TextEdit item displays a block of editable, formatted text.
78 It can display both plain and rich text. For example:
83 text: "<b>Hello</b> <i>World!</i>"
84 font.family: "Helvetica"
91 \image declarative-textedit.gif
93 Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
95 Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
96 to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
98 \snippet snippets/declarative/texteditor.qml 0
100 A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible
101 scrollbar, or a scrollbar that fades in to show location, etc.
103 Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
104 be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
105 from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
107 You can translate between cursor positions (characters from the start of the document) and pixel
108 points using positionAt() and positionToRectangle().
110 \sa Text, TextInput, {declarative/text/textselection}{Text Selection example}
114 \qmlsignal QtQuick2::TextEdit::onLinkActivated(string link)
116 This handler is called when the user clicks on a link embedded in the text.
117 The link must be in rich text or HTML format and the
118 \a link string provides access to the particular link.
120 QQuickTextEdit::QQuickTextEdit(QQuickItem *parent)
121 : QQuickImplicitSizeItem(*(new QQuickTextEditPrivate), parent)
127 QString QQuickTextEdit::text() const
129 Q_D(const QQuickTextEdit);
130 if (!d->textCached) {
131 QQuickTextEditPrivate *d = const_cast<QQuickTextEditPrivate *>(d_func());
132 #ifndef QT_NO_TEXTHTMLPARSER
134 d->text = d->control->toHtml();
137 d->text = d->control->toPlainText();
138 d->textCached = true;
144 \qmlproperty string QtQuick2::TextEdit::font.family
146 Sets the family name of the font.
148 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
149 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
150 If the family isn't available a family will be set using the font matching algorithm.
154 \qmlproperty bool QtQuick2::TextEdit::font.bold
156 Sets whether the font weight is bold.
160 \qmlproperty enumeration QtQuick2::TextEdit::font.weight
162 Sets the font's weight.
164 The weight can be one of:
167 \o Font.Normal - the default
174 TextEdit { text: "Hello"; font.weight: Font.DemiBold }
179 \qmlproperty bool QtQuick2::TextEdit::font.italic
181 Sets whether the font has an italic style.
185 \qmlproperty bool QtQuick2::TextEdit::font.underline
187 Sets whether the text is underlined.
191 \qmlproperty bool QtQuick2::TextEdit::font.strikeout
193 Sets whether the font has a strikeout style.
197 \qmlproperty real QtQuick2::TextEdit::font.pointSize
199 Sets the font size in points. The point size must be greater than zero.
203 \qmlproperty int QtQuick2::TextEdit::font.pixelSize
205 Sets the font size in pixels.
207 Using this function makes the font device dependent. Use
208 \l{TextEdit::font.pointSize} to set the size of the font in a
209 device independent manner.
213 \qmlproperty real QtQuick2::TextEdit::font.letterSpacing
215 Sets the letter spacing for the font.
217 Letter spacing changes the default spacing between individual letters in the font.
218 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
222 \qmlproperty real QtQuick2::TextEdit::font.wordSpacing
224 Sets the word spacing for the font.
226 Word spacing changes the default spacing between individual words.
227 A positive value increases the word spacing by a corresponding amount of pixels,
228 while a negative value decreases the inter-word spacing accordingly.
232 \qmlproperty enumeration QtQuick2::TextEdit::font.capitalization
234 Sets the capitalization for the text.
237 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
238 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
239 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
240 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
241 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
245 TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
250 \qmlproperty string QtQuick2::TextEdit::text
252 The text to display. If the text format is AutoText the text edit will
253 automatically determine whether the text should be treated as
254 rich text. This determination is made using Qt::mightBeRichText().
256 void QQuickTextEdit::setText(const QString &text)
259 if (QQuickTextEdit::text() == text)
262 d->document->clearResources();
263 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
265 #ifndef QT_NO_TEXTHTMLPARSER
266 d->control->setHtml(text);
268 d->control->setPlainText(text);
270 d->useImageFallback = qmlEnableImageCache();
272 d->control->setPlainText(text);
278 \qmlproperty enumeration QtQuick2::TextEdit::textFormat
280 The way the text property should be displayed.
284 \o TextEdit.PlainText
288 The default is TextEdit.PlainText. If the text format is TextEdit.AutoText the text edit
289 will automatically determine whether the text should be treated as
290 rich text. This determination is made using Qt::mightBeRichText().
299 text: "<b>Hello</b> <i>World!</i>"
303 textFormat: TextEdit.RichText
304 text: "<b>Hello</b> <i>World!</i>"
308 textFormat: TextEdit.PlainText
309 text: "<b>Hello</b> <i>World!</i>"
313 \o \image declarative-textformat.png
316 QQuickTextEdit::TextFormat QQuickTextEdit::textFormat() const
318 Q_D(const QQuickTextEdit);
322 void QQuickTextEdit::setTextFormat(TextFormat format)
325 if (format == d->format)
328 bool wasRich = d->richText;
329 d->richText = format == RichText || (format == AutoText && (wasRich || Qt::mightBeRichText(text())));
331 #ifndef QT_NO_TEXTHTMLPARSER
332 if (wasRich && !d->richText) {
333 d->control->setPlainText(!d->textCached ? d->control->toHtml() : d->text);
335 } else if (!wasRich && d->richText) {
336 d->control->setHtml(!d->textCached ? d->control->toPlainText() : d->text);
338 d->useImageFallback = qmlEnableImageCache();
343 d->control->setAcceptRichText(d->format != PlainText);
344 emit textFormatChanged(d->format);
347 QFont QQuickTextEdit::font() const
349 Q_D(const QQuickTextEdit);
350 return d->sourceFont;
353 void QQuickTextEdit::setFont(const QFont &font)
356 if (d->sourceFont == font)
359 d->sourceFont = font;
360 QFont oldFont = d->font;
362 if (d->font.pointSizeF() != -1) {
364 qreal size = qRound(d->font.pointSizeF()*2.0);
365 d->font.setPointSizeF(size/2.0);
368 if (oldFont != d->font) {
369 d->document->setDefaultFont(d->font);
371 d->cursor->setHeight(QFontMetrics(d->font).height());
372 moveCursorDelegate();
376 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
378 emit fontChanged(d->sourceFont);
382 \qmlproperty color QtQuick2::TextEdit::color
387 // green text using hexadecimal notation
388 TextEdit { color: "#00FF00" }
392 // steelblue text using SVG color name
393 TextEdit { color: "steelblue" }
396 QColor QQuickTextEdit::color() const
398 Q_D(const QQuickTextEdit);
402 void QQuickTextEdit::setColor(const QColor &color)
405 if (d->color == color)
409 QPalette pal = d->control->palette();
410 pal.setColor(QPalette::Text, color);
411 d->control->setPalette(pal);
413 emit colorChanged(d->color);
417 \qmlproperty color QtQuick2::TextEdit::selectionColor
419 The text highlight color, used behind selections.
421 QColor QQuickTextEdit::selectionColor() const
423 Q_D(const QQuickTextEdit);
424 return d->selectionColor;
427 void QQuickTextEdit::setSelectionColor(const QColor &color)
430 if (d->selectionColor == color)
433 d->selectionColor = color;
434 QPalette pal = d->control->palette();
435 pal.setColor(QPalette::Highlight, color);
436 d->control->setPalette(pal);
438 emit selectionColorChanged(d->selectionColor);
442 \qmlproperty color QtQuick2::TextEdit::selectedTextColor
444 The selected text color, used in selections.
446 QColor QQuickTextEdit::selectedTextColor() const
448 Q_D(const QQuickTextEdit);
449 return d->selectedTextColor;
452 void QQuickTextEdit::setSelectedTextColor(const QColor &color)
455 if (d->selectedTextColor == color)
458 d->selectedTextColor = color;
459 QPalette pal = d->control->palette();
460 pal.setColor(QPalette::HighlightedText, color);
461 d->control->setPalette(pal);
463 emit selectedTextColorChanged(d->selectedTextColor);
467 \qmlproperty enumeration QtQuick2::TextEdit::horizontalAlignment
468 \qmlproperty enumeration QtQuick2::TextEdit::verticalAlignment
469 \qmlproperty enumeration QtQuick2::TextEdit::effectiveHorizontalAlignment
471 Sets the horizontal and vertical alignment of the text within the TextEdit item's
472 width and height. By default, the text alignment follows the natural alignment
473 of the text, for example text that is read from left to right will be aligned to
476 Valid values for \c horizontalAlignment are:
478 \o TextEdit.AlignLeft (default)
479 \o TextEdit.AlignRight
480 \o TextEdit.AlignHCenter
481 \o TextEdit.AlignJustify
484 Valid values for \c verticalAlignment are:
486 \o TextEdit.AlignTop (default)
487 \o TextEdit.AlignBottom
488 \o TextEdit.AlignVCenter
491 When using the attached property LayoutMirroring::enabled to mirror application
492 layouts, the horizontal alignment of text will also be mirrored. However, the property
493 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
494 of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
496 QQuickTextEdit::HAlignment QQuickTextEdit::hAlign() const
498 Q_D(const QQuickTextEdit);
502 void QQuickTextEdit::setHAlign(HAlignment align)
505 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
506 d->hAlignImplicit = false;
507 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
508 d->updateDefaultTextOption();
513 void QQuickTextEdit::resetHAlign()
516 d->hAlignImplicit = true;
517 if (d->determineHorizontalAlignment() && isComponentComplete()) {
518 d->updateDefaultTextOption();
523 QQuickTextEdit::HAlignment QQuickTextEdit::effectiveHAlign() const
525 Q_D(const QQuickTextEdit);
526 QQuickTextEdit::HAlignment effectiveAlignment = d->hAlign;
527 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
529 case QQuickTextEdit::AlignLeft:
530 effectiveAlignment = QQuickTextEdit::AlignRight;
532 case QQuickTextEdit::AlignRight:
533 effectiveAlignment = QQuickTextEdit::AlignLeft;
539 return effectiveAlignment;
542 bool QQuickTextEditPrivate::setHAlign(QQuickTextEdit::HAlignment alignment, bool forceAlign)
545 if (hAlign != alignment || forceAlign) {
546 QQuickTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
548 emit q->horizontalAlignmentChanged(alignment);
549 if (oldEffectiveHAlign != q->effectiveHAlign())
550 emit q->effectiveHorizontalAlignmentChanged();
556 bool QQuickTextEditPrivate::determineHorizontalAlignment()
559 if (hAlignImplicit && q->isComponentComplete()) {
561 if (document->isEmpty()) {
562 const QString preeditText = control->textCursor().block().layout()->preeditAreaText();
563 alignToRight = preeditText.isEmpty()
564 ? qApp->inputPanel()->inputDirection() == Qt::RightToLeft
565 : preeditText.isRightToLeft();
567 alignToRight = rightToLeftText;
569 return setHAlign(alignToRight ? QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft);
574 void QQuickTextEditPrivate::mirrorChange()
577 if (q->isComponentComplete()) {
578 if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) {
579 updateDefaultTextOption();
581 emit q->effectiveHorizontalAlignmentChanged();
586 QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const
588 Q_D(const QQuickTextEdit);
592 void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment)
595 if (alignment == d->vAlign)
597 d->vAlign = alignment;
598 d->updateDefaultTextOption();
600 moveCursorDelegate();
601 emit verticalAlignmentChanged(d->vAlign);
604 \qmlproperty enumeration QtQuick2::TextEdit::wrapMode
606 Set this property to wrap the text to the TextEdit item's width.
607 The text will only wrap if an explicit width has been set.
610 \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
611 \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
612 \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
613 \o 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.
616 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
618 QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode() const
620 Q_D(const QQuickTextEdit);
624 void QQuickTextEdit::setWrapMode(WrapMode mode)
627 if (mode == d->wrapMode)
630 d->updateDefaultTextOption();
632 emit wrapModeChanged();
636 \qmlproperty int QtQuick2::TextEdit::lineCount
638 Returns the total number of lines in the textEdit item.
640 int QQuickTextEdit::lineCount() const
642 Q_D(const QQuickTextEdit);
647 \qmlproperty int QtQuick2::TextEdit::length
649 Returns the total number of plain text characters in the TextEdit item.
651 As this number doesn't include any formatting markup it may not be the same as the
652 length of the string returned by the \l text property.
654 This property can be faster than querying the length the \l text property as it doesn't
655 require any copying or conversion of the TextEdit's internal string data.
658 int QQuickTextEdit::length() const
660 Q_D(const QQuickTextEdit);
661 // QTextDocument::characterCount() includes the terminating null character.
662 return qMax(0, d->document->characterCount() - 1);
666 \qmlproperty real QtQuick2::TextEdit::paintedWidth
668 Returns the width of the text, including the width past the width
669 which is covered due to insufficient wrapping if \l wrapMode is set.
671 qreal QQuickTextEdit::paintedWidth() const
673 Q_D(const QQuickTextEdit);
674 return d->paintedSize.width();
678 \qmlproperty real QtQuick2::TextEdit::paintedHeight
680 Returns the height of the text, including the height past the height
681 that is covered if the text does not fit within the set height.
683 qreal QQuickTextEdit::paintedHeight() const
685 Q_D(const QQuickTextEdit);
686 return d->paintedSize.height();
690 \qmlproperty url QtQuick2::TextEdit::baseUrl
692 This property specifies a base URL which is used to resolve relative URLs
695 By default is the url of the TextEdit element.
698 QUrl QQuickTextEdit::baseUrl() const
700 Q_D(const QQuickTextEdit);
701 if (d->baseUrl.isEmpty()) {
702 if (QDeclarativeContext *context = qmlContext(this))
703 const_cast<QQuickTextEditPrivate *>(d)->baseUrl = context->baseUrl();
708 void QQuickTextEdit::setBaseUrl(const QUrl &url)
711 if (baseUrl() != url) {
714 d->document->setBaseUrl(url, d->richText);
715 emit baseUrlChanged();
719 void QQuickTextEdit::resetBaseUrl()
721 if (QDeclarativeContext *context = qmlContext(this))
722 setBaseUrl(context->baseUrl());
728 \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position)
730 Returns the rectangle at the given \a position in the text. The x, y,
731 and height properties correspond to the cursor that would describe
734 QRectF QQuickTextEdit::positionToRectangle(int pos) const
736 Q_D(const QQuickTextEdit);
737 QTextCursor c(d->document);
739 return d->control->cursorRect(c);
744 \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y)
746 Returns the text position closest to pixel position (\a x, \a y).
748 Position 0 is before the first character, position 1 is after the first character
749 but before the second, and so on until position \l {text}.length, which is after all characters.
751 int QQuickTextEdit::positionAt(int x, int y) const
753 Q_D(const QQuickTextEdit);
754 int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
755 QTextCursor cursor = d->control->textCursor();
756 if (r > cursor.position()) {
757 // The cursor position includes positions within the preedit text, but only positions in the
758 // same text block are offset so it is possible to get a position that is either part of the
759 // preedit or the next text block.
760 QTextLayout *layout = cursor.block().layout();
761 const int preeditLength = layout
762 ? layout->preeditAreaText().length()
764 if (preeditLength > 0
765 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
766 r = r > cursor.position() + preeditLength
775 \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
777 Moves the cursor to \a position and updates the selection according to the optional \a mode
778 parameter. (To only move the cursor, set the \l cursorPosition property.)
780 When this method is called it additionally sets either the
781 selectionStart or the selectionEnd (whichever was at the previous cursor position)
782 to the specified position. This allows you to easily extend and contract the selected
785 The selection mode specifies whether the selection is updated on a per character or a per word
786 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
789 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
790 the previous cursor position) to the specified position.
791 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
792 words between the specified position and the previous cursor position. Words partially in the
796 For example, take this sequence of calls:
800 moveCursorSelection(9, TextEdit.SelectCharacters)
801 moveCursorSelection(7, TextEdit.SelectCharacters)
804 This moves the cursor to position 5, extend the selection end from 5 to 9
805 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
806 selected (the 6th and 7th characters).
808 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
809 before or on position 5 and extend the selection end to a word boundary on or past position 9.
811 void QQuickTextEdit::moveCursorSelection(int pos)
813 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
815 QTextCursor cursor = d->control->textCursor();
816 if (cursor.position() == pos)
818 cursor.setPosition(pos, QTextCursor::KeepAnchor);
819 d->control->setTextCursor(cursor);
822 void QQuickTextEdit::moveCursorSelection(int pos, SelectionMode mode)
825 QTextCursor cursor = d->control->textCursor();
826 if (cursor.position() == pos)
828 if (mode == SelectCharacters) {
829 cursor.setPosition(pos, QTextCursor::KeepAnchor);
830 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
831 if (cursor.anchor() > cursor.position()) {
832 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
833 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
834 if (cursor.position() == cursor.anchor())
835 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
837 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
839 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
840 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
843 cursor.setPosition(pos, QTextCursor::KeepAnchor);
844 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
845 if (cursor.position() != pos)
846 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
847 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
848 if (cursor.anchor() < cursor.position()) {
849 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
850 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
852 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
853 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
854 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
855 if (cursor.position() != cursor.anchor()) {
856 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
857 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
861 cursor.setPosition(pos, QTextCursor::KeepAnchor);
862 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
863 if (cursor.position() != pos) {
864 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
865 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
868 d->control->setTextCursor(cursor);
872 \qmlproperty bool QtQuick2::TextEdit::cursorVisible
873 If true the text edit shows a cursor.
875 This property is set and unset when the text edit gets active focus, but it can also
876 be set directly (useful, for example, if a KeyProxy might forward keys to it).
878 bool QQuickTextEdit::isCursorVisible() const
880 Q_D(const QQuickTextEdit);
881 return d->cursorVisible;
884 void QQuickTextEdit::setCursorVisible(bool on)
887 if (d->cursorVisible == on)
889 d->cursorVisible = on;
890 QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
891 if (!on && !d->persistentSelection)
892 d->control->setCursorIsFocusIndicator(true);
893 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
894 emit cursorVisibleChanged(d->cursorVisible);
898 \qmlproperty int QtQuick2::TextEdit::cursorPosition
899 The position of the cursor in the TextEdit.
901 int QQuickTextEdit::cursorPosition() const
903 Q_D(const QQuickTextEdit);
904 return d->control->textCursor().position();
907 void QQuickTextEdit::setCursorPosition(int pos)
910 if (pos < 0 || pos >= d->document->characterCount()) // characterCount includes the terminating null.
912 QTextCursor cursor = d->control->textCursor();
913 if (cursor.position() == pos && cursor.anchor() == pos)
915 cursor.setPosition(pos);
916 d->control->setTextCursor(cursor);
920 \qmlproperty Component QtQuick2::TextEdit::cursorDelegate
921 The delegate for the cursor in the TextEdit.
923 If you set a cursorDelegate for a TextEdit, this delegate will be used for
924 drawing the cursor instead of the standard cursor. An instance of the
925 delegate will be created and managed by the text edit when a cursor is
926 needed, and the x and y properties of delegate instance will be set so as
927 to be one pixel before the top left of the current character.
929 Note that the root item of the delegate component must be a QDeclarativeItem or
930 QDeclarativeItem derived item.
932 QDeclarativeComponent* QQuickTextEdit::cursorDelegate() const
934 Q_D(const QQuickTextEdit);
935 return d->cursorComponent;
938 void QQuickTextEdit::setCursorDelegate(QDeclarativeComponent* c)
941 if (d->cursorComponent) {
943 d->control->setCursorWidth(-1);
949 d->cursorComponent = c;
950 if (c && c->isReady()) {
951 loadCursorDelegate();
954 connect(c, SIGNAL(statusChanged()),
955 this, SLOT(loadCursorDelegate()));
958 emit cursorDelegateChanged();
961 void QQuickTextEdit::loadCursorDelegate()
964 if (d->cursorComponent->isLoading())
966 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
967 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
968 d->cursor = qobject_cast<QQuickItem*>(object);
970 d->control->setCursorWidth(0);
972 QDeclarative_setParent_noEvent(d->cursor, this);
973 d->cursor->setParentItem(this);
974 d->cursor->setHeight(QFontMetrics(d->font).height());
975 moveCursorDelegate();
978 qmlInfo(this) << "Error loading cursor delegate.";
983 \qmlproperty int QtQuick2::TextEdit::selectionStart
985 The cursor position before the first character in the current selection.
987 This property is read-only. To change the selection, use select(start,end),
988 selectAll(), or selectWord().
990 \sa selectionEnd, cursorPosition, selectedText
992 int QQuickTextEdit::selectionStart() const
994 Q_D(const QQuickTextEdit);
995 return d->control->textCursor().selectionStart();
999 \qmlproperty int QtQuick2::TextEdit::selectionEnd
1001 The cursor position after the last character in the current selection.
1003 This property is read-only. To change the selection, use select(start,end),
1004 selectAll(), or selectWord().
1006 \sa selectionStart, cursorPosition, selectedText
1008 int QQuickTextEdit::selectionEnd() const
1010 Q_D(const QQuickTextEdit);
1011 return d->control->textCursor().selectionEnd();
1015 \qmlproperty string QtQuick2::TextEdit::selectedText
1017 This read-only property provides the text currently selected in the
1020 It is equivalent to the following snippet, but is faster and easier
1023 //myTextEdit is the id of the TextEdit
1024 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
1025 myTextEdit.selectionEnd);
1028 QString QQuickTextEdit::selectedText() const
1030 Q_D(const QQuickTextEdit);
1031 return d->control->textCursor().selectedText();
1035 \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress
1037 Whether the TextEdit should gain active focus on a mouse press. By default this is
1040 bool QQuickTextEdit::focusOnPress() const
1042 Q_D(const QQuickTextEdit);
1043 return d->focusOnPress;
1046 void QQuickTextEdit::setFocusOnPress(bool on)
1048 Q_D(QQuickTextEdit);
1049 if (d->focusOnPress == on)
1051 d->focusOnPress = on;
1052 emit activeFocusOnPressChanged(d->focusOnPress);
1056 \qmlproperty bool QtQuick2::TextEdit::persistentSelection
1058 Whether the TextEdit should keep the selection visible when it loses active focus to another
1059 item in the scene. By default this is set to true;
1061 bool QQuickTextEdit::persistentSelection() const
1063 Q_D(const QQuickTextEdit);
1064 return d->persistentSelection;
1067 void QQuickTextEdit::setPersistentSelection(bool on)
1069 Q_D(QQuickTextEdit);
1070 if (d->persistentSelection == on)
1072 d->persistentSelection = on;
1073 emit persistentSelectionChanged(d->persistentSelection);
1077 \qmlproperty real QtQuick2::TextEdit::textMargin
1079 The margin, in pixels, around the text in the TextEdit.
1081 qreal QQuickTextEdit::textMargin() const
1083 Q_D(const QQuickTextEdit);
1084 return d->textMargin;
1087 void QQuickTextEdit::setTextMargin(qreal margin)
1089 Q_D(QQuickTextEdit);
1090 if (d->textMargin == margin)
1092 d->textMargin = margin;
1093 d->document->setDocumentMargin(d->textMargin);
1094 emit textMarginChanged(d->textMargin);
1098 \qmlproperty enumeration QtQuick2::TextEdit::inputMethodHints
1100 Provides hints to the input method about the expected content of the text edit and how it
1103 The value is a bit-wise combination of flags or Qt.ImhNone if no hints are set.
1105 Flags that alter behaviour are:
1108 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1109 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1110 in any persistent storage like predictive user dictionary.
1111 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1112 when a sentence ends.
1113 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1114 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1115 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1116 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1118 \o Qt.ImhDate - The text editor functions as a date field.
1119 \o Qt.ImhTime - The text editor functions as a time field.
1122 Flags that restrict input (exclusive flags) are:
1125 \o Qt.ImhDigitsOnly - Only digits are allowed.
1126 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1127 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1128 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1129 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1130 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1131 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1137 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1141 void QQuickTextEdit::geometryChanged(const QRectF &newGeometry,
1142 const QRectF &oldGeometry)
1144 if (newGeometry.width() != oldGeometry.width())
1146 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1150 Ensures any delayed caching or data loading the class
1151 needs to performed is complete.
1153 void QQuickTextEdit::componentComplete()
1155 Q_D(QQuickTextEdit);
1156 QQuickImplicitSizeItem::componentComplete();
1158 d->document->setBaseUrl(baseUrl(), d->richText);
1160 d->useImageFallback = qmlEnableImageCache();
1163 d->determineHorizontalAlignment();
1164 d->updateDefaultTextOption();
1171 \qmlproperty bool QtQuick2::TextEdit::selectByMouse
1175 If true, the user can use the mouse to select text in some
1176 platform-specific way. Note that for some platforms this may
1177 not be an appropriate interaction (eg. may conflict with how
1178 the text needs to behave inside a Flickable.
1180 bool QQuickTextEdit::selectByMouse() const
1182 Q_D(const QQuickTextEdit);
1183 return d->selectByMouse;
1186 void QQuickTextEdit::setSelectByMouse(bool on)
1188 Q_D(QQuickTextEdit);
1189 if (d->selectByMouse != on) {
1190 d->selectByMouse = on;
1191 setKeepMouseGrab(on);
1193 setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1195 setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1196 emit selectByMouseChanged(on);
1201 \qmlproperty enum QtQuick2::TextEdit::mouseSelectionMode
1203 Specifies how text should be selected using a mouse.
1206 \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1207 \o TextEdit.SelectWords - The selection is updated with whole words.
1210 This property only applies when \l selectByMouse is true.
1212 QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode() const
1214 Q_D(const QQuickTextEdit);
1215 return d->mouseSelectionMode;
1218 void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode)
1220 Q_D(QQuickTextEdit);
1221 if (d->mouseSelectionMode != mode) {
1222 d->mouseSelectionMode = mode;
1223 d->control->setWordSelectionEnabled(mode == SelectWords);
1224 emit mouseSelectionModeChanged(mode);
1229 \qmlproperty bool QtQuick2::TextEdit::readOnly
1231 Whether the user can interact with the TextEdit item. If this
1232 property is set to true the text cannot be edited by user interaction.
1234 By default this property is false.
1236 void QQuickTextEdit::setReadOnly(bool r)
1238 Q_D(QQuickTextEdit);
1239 if (r == isReadOnly())
1242 setFlag(QQuickItem::ItemAcceptsInputMethod, !r);
1243 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1244 if (d->selectByMouse)
1245 flags = flags | Qt::TextSelectableByMouse;
1247 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1248 d->control->setTextInteractionFlags(flags);
1250 d->control->moveCursor(QTextCursor::End);
1252 updateInputMethod(Qt::ImEnabled);
1253 q_canPasteChanged();
1254 emit readOnlyChanged(r);
1257 bool QQuickTextEdit::isReadOnly() const
1259 Q_D(const QQuickTextEdit);
1260 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1264 Sets how the text edit should interact with user input to the given
1267 void QQuickTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1269 Q_D(QQuickTextEdit);
1270 d->control->setTextInteractionFlags(flags);
1274 Returns the flags specifying how the text edit should interact
1277 Qt::TextInteractionFlags QQuickTextEdit::textInteractionFlags() const
1279 Q_D(const QQuickTextEdit);
1280 return d->control->textInteractionFlags();
1284 \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle
1286 The rectangle where the standard text cursor is rendered
1287 within the text edit. Read-only.
1289 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
1290 automatically when it changes. The width of the delegate is unaffected by changes in the
1293 QRect QQuickTextEdit::cursorRectangle() const
1295 Q_D(const QQuickTextEdit);
1296 return d->control->cursorRect().toRect().translated(0,d->yoff);
1299 bool QQuickTextEdit::event(QEvent *event)
1301 Q_D(QQuickTextEdit);
1302 if (event->type() == QEvent::ShortcutOverride) {
1303 d->control->processEvent(event, QPointF(0, -d->yoff));
1304 return event->isAccepted();
1306 return QQuickImplicitSizeItem::event(event);
1311 Handles the given key \a event.
1313 void QQuickTextEdit::keyPressEvent(QKeyEvent *event)
1315 Q_D(QQuickTextEdit);
1316 d->control->processEvent(event, QPointF(0, -d->yoff));
1317 if (!event->isAccepted())
1318 QQuickImplicitSizeItem::keyPressEvent(event);
1323 Handles the given key \a event.
1325 void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event)
1327 Q_D(QQuickTextEdit);
1328 d->control->processEvent(event, QPointF(0, -d->yoff));
1329 if (!event->isAccepted())
1330 QQuickImplicitSizeItem::keyReleaseEvent(event);
1334 \qmlmethod void QtQuick2::TextEdit::deselect()
1336 Removes active text selection.
1338 void QQuickTextEdit::deselect()
1340 Q_D(QQuickTextEdit);
1341 QTextCursor c = d->control->textCursor();
1343 d->control->setTextCursor(c);
1347 \qmlmethod void QtQuick2::TextEdit::selectAll()
1349 Causes all text to be selected.
1351 void QQuickTextEdit::selectAll()
1353 Q_D(QQuickTextEdit);
1354 d->control->selectAll();
1358 \qmlmethod void QtQuick2::TextEdit::selectWord()
1360 Causes the word closest to the current cursor position to be selected.
1362 void QQuickTextEdit::selectWord()
1364 Q_D(QQuickTextEdit);
1365 QTextCursor c = d->control->textCursor();
1366 c.select(QTextCursor::WordUnderCursor);
1367 d->control->setTextCursor(c);
1371 \qmlmethod void QtQuick2::TextEdit::select(int start, int end)
1373 Causes the text from \a start to \a end to be selected.
1375 If either start or end is out of range, the selection is not changed.
1377 After calling this, selectionStart will become the lesser
1378 and selectionEnd will become the greater (regardless of the order passed
1381 \sa selectionStart, selectionEnd
1383 void QQuickTextEdit::select(int start, int end)
1385 Q_D(QQuickTextEdit);
1386 if (start < 0 || end < 0 || start >= d->document->characterCount() || end >= d->document->characterCount())
1388 QTextCursor cursor = d->control->textCursor();
1389 cursor.beginEditBlock();
1390 cursor.setPosition(start, QTextCursor::MoveAnchor);
1391 cursor.setPosition(end, QTextCursor::KeepAnchor);
1392 cursor.endEditBlock();
1393 d->control->setTextCursor(cursor);
1396 updateSelectionMarkers();
1400 \qmlmethod void QtQuick2::TextEdit::isRightToLeft(int start, int end)
1402 Returns true if the natural reading direction of the editor text
1403 found between positions \a start and \a end is right to left.
1405 bool QQuickTextEdit::isRightToLeft(int start, int end)
1408 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1411 return getText(start, end).isRightToLeft();
1415 #ifndef QT_NO_CLIPBOARD
1417 \qmlmethod QtQuick2::TextEdit::cut()
1419 Moves the currently selected text to the system clipboard.
1421 void QQuickTextEdit::cut()
1423 Q_D(QQuickTextEdit);
1428 \qmlmethod QtQuick2::TextEdit::copy()
1430 Copies the currently selected text to the system clipboard.
1432 void QQuickTextEdit::copy()
1434 Q_D(QQuickTextEdit);
1439 \qmlmethod QtQuick2::TextEdit::paste()
1441 Replaces the currently selected text by the contents of the system clipboard.
1443 void QQuickTextEdit::paste()
1445 Q_D(QQuickTextEdit);
1446 d->control->paste();
1448 #endif // QT_NO_CLIPBOARD
1452 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1453 current selection, and updates the selection start to the current cursor
1457 void QQuickTextEdit::undo()
1459 Q_D(QQuickTextEdit);
1464 Redoes the last operation if redo is \l {canRedo}{available}.
1467 void QQuickTextEdit::redo()
1469 Q_D(QQuickTextEdit);
1475 Handles the given mouse \a event.
1477 void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
1479 Q_D(QQuickTextEdit);
1480 if (d->focusOnPress){
1481 bool hadActiveFocus = hasActiveFocus();
1483 // re-open input panel on press if already focused
1484 if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
1485 openSoftwareInputPanel();
1487 d->control->processEvent(event, QPointF(0, -d->yoff));
1488 if (!event->isAccepted())
1489 QQuickImplicitSizeItem::mousePressEvent(event);
1494 Handles the given mouse \a event.
1496 void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
1498 Q_D(QQuickTextEdit);
1499 d->control->processEvent(event, QPointF(0, -d->yoff));
1501 if (!event->isAccepted())
1502 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1507 Handles the given mouse \a event.
1509 void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
1511 Q_D(QQuickTextEdit);
1512 d->control->processEvent(event, QPointF(0, -d->yoff));
1513 if (!event->isAccepted())
1514 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1519 Handles the given mouse \a event.
1521 void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
1523 Q_D(QQuickTextEdit);
1524 d->control->processEvent(event, QPointF(0, -d->yoff));
1525 if (!event->isAccepted())
1526 QQuickImplicitSizeItem::mouseMoveEvent(event);
1531 Handles the given input method \a event.
1533 void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
1535 Q_D(QQuickTextEdit);
1536 const bool wasComposing = isInputMethodComposing();
1537 d->control->processEvent(event, QPointF(0, -d->yoff));
1538 if (wasComposing != isInputMethodComposing())
1539 emit inputMethodComposingChanged();
1542 void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1544 if (change == ItemActiveFocusHasChanged) {
1545 setCursorVisible(value.boolValue); // ### refactor: focus handling && d->canvas && d->canvas->hasFocus());
1547 if (value.boolValue) {
1548 q_updateAlignment();
1549 connect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1550 this, SLOT(q_updateAlignment()));
1552 disconnect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1553 this, SLOT(q_updateAlignment()));
1556 QQuickItem::itemChange(change, value);
1561 Returns the value of the given \a property.
1563 QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1565 Q_D(const QQuickTextEdit);
1570 v = (bool)(flags() & ItemAcceptsInputMethod);
1573 v = (int)inputMethodHints();
1576 v = d->control->inputMethodQuery(property);
1583 void QQuickTextEdit::updateImageCache(const QRectF &)
1585 Q_D(QQuickTextEdit);
1587 // Do we really need the image cache?
1588 if (!d->richText || !d->useImageFallback) {
1589 if (!d->pixmapCache.isNull())
1590 d->pixmapCache = QPixmap();
1594 if (width() != d->pixmapCache.width() || height() != d->pixmapCache.height())
1595 d->pixmapCache = QPixmap(width(), height());
1597 if (d->pixmapCache.isNull())
1600 // ### Use supplied rect, clear area and update only this part (for cursor updates)
1601 QRectF bounds = QRectF(0, 0, width(), height());
1602 d->pixmapCache.fill(Qt::transparent);
1604 QPainter painter(&d->pixmapCache);
1606 painter.setRenderHint(QPainter::TextAntialiasing);
1607 painter.translate(0, d->yoff);
1609 d->control->drawContents(&painter, bounds);
1614 void QQuickTextEdit::triggerPreprocess()
1616 Q_D(QQuickTextEdit);
1617 if (d->updateType == QQuickTextEditPrivate::UpdateNone)
1618 d->updateType = QQuickTextEditPrivate::UpdateOnlyPreprocess;
1622 QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1624 Q_UNUSED(updatePaintNodeData);
1625 Q_D(QQuickTextEdit);
1627 if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode && oldNode != 0) {
1628 // Update done in preprocess() in the nodes
1629 d->updateType = QQuickTextEditPrivate::UpdateNone;
1633 d->updateType = QQuickTextEditPrivate::UpdateNone;
1635 QSGNode *currentNode = oldNode;
1636 if (d->richText && d->useImageFallback) {
1637 QSGImageNode *node = 0;
1638 if (oldNode == 0 || d->nodeType != QQuickTextEditPrivate::NodeIsTexture) {
1640 node = QQuickItemPrivate::get(this)->sceneGraphContext()->createImageNode();
1641 d->texture = new QSGPlainTexture();
1642 d->nodeType = QQuickTextEditPrivate::NodeIsTexture;
1645 node = static_cast<QSGImageNode *>(oldNode);
1648 qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->pixmapCache.toImage());
1649 node->setTexture(0);
1650 node->setTexture(d->texture);
1652 node->setTargetRect(QRectF(0, 0, d->pixmapCache.width(), d->pixmapCache.height()));
1653 node->setSourceRect(QRectF(0, 0, 1, 1));
1654 node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
1655 node->setVerticalWrapMode(QSGTexture::ClampToEdge);
1656 node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that..
1659 } else if (oldNode == 0 || d->documentDirty) {
1660 d->documentDirty = false;
1662 #if defined(Q_OS_MAC)
1663 // Make sure document is relayouted in the paint node on Mac
1664 // to avoid crashes due to the font engines created in the
1666 d->document->markContentsDirty(0, d->document->characterCount());
1669 QQuickTextNode *node = 0;
1670 if (oldNode == 0 || d->nodeType != QQuickTextEditPrivate::NodeIsText) {
1672 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1673 d->nodeType = QQuickTextEditPrivate::NodeIsText;
1676 node = static_cast<QQuickTextNode *>(oldNode);
1679 node->deleteContent();
1680 node->setMatrix(QMatrix4x4());
1682 QRectF bounds = boundingRect();
1684 QColor selectionColor = d->control->palette().color(QPalette::Highlight);
1685 QColor selectedTextColor = d->control->palette().color(QPalette::HighlightedText);
1686 node->addTextDocument(bounds.topLeft(), d->document, d->color, QQuickText::Normal, QColor(),
1687 selectionColor, selectedTextColor, selectionStart(),
1688 selectionEnd() - 1); // selectionEnd() returns first char after
1691 #if defined(Q_OS_MAC)
1692 // We also need to make sure the document layout is redone when
1693 // control is returned to the main thread, as all the font engines
1694 // are now owned by the rendering thread
1695 d->document->markContentsDirty(0, d->document->characterCount());
1699 if (d->nodeType == QQuickTextEditPrivate::NodeIsText && d->cursorComponent == 0 && !isReadOnly()) {
1700 QQuickTextNode *node = static_cast<QQuickTextNode *>(currentNode);
1702 QColor color = (!d->cursorVisible || !d->control->cursorOn())
1703 ? QColor(0, 0, 0, 0)
1706 if (node->cursorNode() == 0) {
1707 node->setCursor(cursorRectangle(), color);
1709 node->cursorNode()->setRect(cursorRectangle());
1710 node->cursorNode()->setColor(color);
1719 \qmlproperty bool QtQuick2::TextEdit::smooth
1721 This property holds whether the text is smoothly scaled or transformed.
1723 Smooth filtering gives better visual quality, but is slower. If
1724 the item is displayed at its natural size, this property has no visual or
1727 \note Generally scaling artifacts are only visible if the item is stationary on
1728 the screen. A common pattern when animating an item is to disable smooth
1729 filtering at the beginning of the animation and reenable it at the conclusion.
1733 \qmlproperty bool QtQuick2::TextEdit::canPaste
1735 Returns true if the TextEdit is writable and the content of the clipboard is
1736 suitable for pasting into the TextEdit.
1738 bool QQuickTextEdit::canPaste() const
1740 Q_D(const QQuickTextEdit);
1741 if (!d->canPasteValid) {
1742 const_cast<QQuickTextEditPrivate *>(d)->canPaste = d->control->canPaste();
1743 const_cast<QQuickTextEditPrivate *>(d)->canPasteValid = true;
1749 \qmlproperty bool QtQuick2::TextEdit::canUndo
1751 Returns true if the TextEdit is writable and there are previous operations
1755 bool QQuickTextEdit::canUndo() const
1757 Q_D(const QQuickTextEdit);
1758 return d->document->isUndoAvailable();
1762 \qmlproperty bool QtQuick2::TextEdit::canRedo
1764 Returns true if the TextEdit is writable and there are \l {undo}{undone}
1765 operations that can be redone.
1768 bool QQuickTextEdit::canRedo() const
1770 Q_D(const QQuickTextEdit);
1771 return d->document->isRedoAvailable();
1775 \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1778 This property holds whether the TextEdit has partial text input from an
1781 While it is composing an input method may rely on mouse or key events from
1782 the TextEdit to edit or commit the partial text. This property can be used
1783 to determine when to disable events handlers that may interfere with the
1784 correct operation of an input method.
1786 bool QQuickTextEdit::isInputMethodComposing() const
1788 Q_D(const QQuickTextEdit);
1789 if (QTextLayout *layout = d->control->textCursor().block().layout())
1790 return layout->preeditAreaText().length() > 0;
1794 void QQuickTextEditPrivate::init()
1796 Q_Q(QQuickTextEdit);
1798 q->setSmooth(smooth);
1799 q->setAcceptedMouseButtons(Qt::LeftButton);
1800 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1801 q->setFlag(QQuickItem::ItemHasContents);
1803 document = new QQuickTextDocumentWithImageResources(q);
1805 control = new QQuickTextControl(document, q);
1806 control->setView(q);
1807 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1808 control->setAcceptRichText(false);
1810 // QQuickTextControl follows the default text color
1811 // defined by the platform, declarative text
1812 // should be black by default
1813 QPalette pal = control->palette();
1814 if (pal.color(QPalette::Text) != color) {
1815 pal.setColor(QPalette::Text, color);
1816 control->setPalette(pal);
1819 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateDocument()));
1820 QObject::connect(control, SIGNAL(updateCursorRequest()), q, SLOT(updateCursor()));
1821 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1822 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1823 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1824 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1825 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1826 QObject::connect(control, SIGNAL(cursorRectangleChanged()), q, SLOT(moveCursorDelegate()));
1827 QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1828 #ifndef QT_NO_CLIPBOARD
1829 QObject::connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1831 FAST_CONNECT(document, SIGNAL(undoAvailable(bool)), q, SIGNAL(canUndoChanged()));
1832 FAST_CONNECT(document, SIGNAL(redoAvailable(bool)), q, SIGNAL(canRedoChanged()));
1833 FAST_CONNECT(document, SIGNAL(imagesLoaded()), q, SLOT(updateSize()));
1835 document->setDefaultFont(font);
1836 document->setDocumentMargin(textMargin);
1837 document->setUndoRedoEnabled(false); // flush undo buffer.
1838 document->setUndoRedoEnabled(true);
1839 updateDefaultTextOption();
1842 void QQuickTextEdit::q_textChanged()
1844 Q_D(QQuickTextEdit);
1845 d->textCached = false;
1846 d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
1847 d->determineHorizontalAlignment();
1848 d->updateDefaultTextOption();
1854 void QQuickTextEdit::moveCursorDelegate()
1856 Q_D(QQuickTextEdit);
1857 d->determineHorizontalAlignment();
1858 updateInputMethod();
1859 emit cursorRectangleChanged();
1862 QRectF cursorRect = cursorRectangle();
1863 d->cursor->setX(cursorRect.x());
1864 d->cursor->setY(cursorRect.y());
1867 void QQuickTextEdit::updateSelectionMarkers()
1869 Q_D(QQuickTextEdit);
1870 if (d->lastSelectionStart != d->control->textCursor().selectionStart()) {
1871 d->lastSelectionStart = d->control->textCursor().selectionStart();
1872 emit selectionStartChanged();
1874 if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) {
1875 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1876 emit selectionEndChanged();
1880 QRectF QQuickTextEdit::boundingRect() const
1882 Q_D(const QQuickTextEdit);
1883 QRectF r = QQuickImplicitSizeItem::boundingRect();
1884 int cursorWidth = 1;
1886 cursorWidth = d->cursor->width();
1887 if (!d->document->isEmpty())
1888 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1890 // Could include font max left/right bearings to either side of rectangle.
1892 r.setRight(r.right() + cursorWidth);
1893 return r.translated(0,d->yoff);
1896 qreal QQuickTextEditPrivate::getImplicitWidth() const
1898 Q_Q(const QQuickTextEdit);
1899 if (!requireImplicitWidth) {
1900 // We don't calculate implicitWidth unless it is required.
1901 // We need to force a size update now to ensure implicitWidth is calculated
1902 const_cast<QQuickTextEditPrivate*>(this)->requireImplicitWidth = true;
1903 const_cast<QQuickTextEdit*>(q)->updateSize();
1905 return implicitWidth;
1908 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1909 // need to do all the calculations each time
1910 void QQuickTextEdit::updateSize()
1912 Q_D(QQuickTextEdit);
1913 if (isComponentComplete()) {
1914 qreal naturalWidth = d->implicitWidth;
1915 // ### assumes that if the width is set, the text will fill to edges
1916 // ### (unless wrap is false, then clipping will occur)
1918 if (!d->requireImplicitWidth) {
1919 emit implicitWidthChanged();
1920 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1921 if (d->requireImplicitWidth)
1924 if (d->requireImplicitWidth) {
1925 d->document->setTextWidth(-1);
1926 naturalWidth = d->document->idealWidth();
1928 if (d->document->textWidth() != width())
1929 d->document->setTextWidth(width());
1931 d->document->setTextWidth(-1);
1933 QFontMetrics fm = QFontMetrics(d->font);
1935 dy -= (int)d->document->size().height();
1938 if (heightValid()) {
1939 if (d->vAlign == AlignBottom)
1941 else if (d->vAlign == AlignVCenter)
1948 if (nyoff != d->yoff)
1950 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1952 //### need to comfirm cost of always setting these
1953 int newWidth = qCeil(d->document->idealWidth());
1954 if (!widthValid() && d->document->textWidth() != newWidth)
1955 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1956 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1960 else if (d->requireImplicitWidth)
1961 iWidth = naturalWidth;
1962 qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
1964 setImplicitSize(iWidth, newHeight);
1966 setImplicitHeight(newHeight);
1968 d->paintedSize = QSize(newWidth, newHeight);
1969 emit paintedSizeChanged();
1976 void QQuickTextEdit::updateDocument()
1978 Q_D(QQuickTextEdit);
1979 d->documentDirty = true;
1981 if (isComponentComplete()) {
1983 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1988 void QQuickTextEdit::updateCursor()
1990 Q_D(QQuickTextEdit);
1991 if (isComponentComplete()) {
1992 updateImageCache(d->control->cursorRect());
1993 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1998 void QQuickTextEdit::q_updateAlignment()
2000 Q_D(QQuickTextEdit);
2001 if (d->determineHorizontalAlignment()) {
2002 d->updateDefaultTextOption();
2003 moveCursorDelegate();
2007 void QQuickTextEdit::updateTotalLines()
2009 Q_D(QQuickTextEdit);
2013 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
2014 QTextLayout *layout = it.layout();
2017 subLines += layout->lineCount()-1;
2020 int newTotalLines = d->document->lineCount() + subLines;
2021 if (d->lineCount != newTotalLines) {
2022 d->lineCount = newTotalLines;
2023 emit lineCountChanged();
2027 void QQuickTextEditPrivate::updateDefaultTextOption()
2029 Q_Q(QQuickTextEdit);
2030 QTextOption opt = document->defaultTextOption();
2031 int oldAlignment = opt.alignment();
2033 QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
2034 if (rightToLeftText) {
2035 if (horizontalAlignment == QQuickTextEdit::AlignLeft)
2036 horizontalAlignment = QQuickTextEdit::AlignRight;
2037 else if (horizontalAlignment == QQuickTextEdit::AlignRight)
2038 horizontalAlignment = QQuickTextEdit::AlignLeft;
2040 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
2042 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
2043 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
2045 bool oldUseDesignMetrics = opt.useDesignMetrics();
2046 bool useDesignMetrics = !qmlDisableDistanceField();
2047 opt.setUseDesignMetrics(useDesignMetrics);
2049 if (oldWrapMode == opt.wrapMode()
2050 && oldAlignment == opt.alignment()
2051 && oldUseDesignMetrics == useDesignMetrics) {
2054 document->setDefaultTextOption(opt);
2060 \qmlmethod void QtQuick2::TextEdit::openSoftwareInputPanel()
2062 Opens software input panels like virtual keyboards for typing, useful for
2063 customizing when you want the input keyboard to be shown and hidden in
2066 By default the opening of input panels follows the platform style. Input panels are
2067 always closed if no editor has active focus.
2069 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2070 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2071 the behavior you want.
2073 Only relevant on platforms, which provide virtual keyboards.
2079 text: "Hello world!"
2080 activeFocusOnPress: false
2082 anchors.fill: parent
2084 if (!textEdit.activeFocus) {
2085 textEdit.forceActiveFocus();
2086 textEdit.openSoftwareInputPanel();
2088 textEdit.focus = false;
2091 onPressAndHold: textEdit.closeSoftwareInputPanel();
2096 void QQuickTextEdit::openSoftwareInputPanel()
2099 qGuiApp->inputPanel()->show();
2103 \qmlmethod void QtQuick2::TextEdit::closeSoftwareInputPanel()
2105 Closes a software input panel like a virtual keyboard shown on the screen, useful
2106 for customizing when you want the input keyboard to be shown and hidden in
2109 By default the opening of input panels follows the platform style. Input panels are
2110 always closed if no editor has active focus.
2112 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2113 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2114 the behavior you want.
2116 Only relevant on platforms, which provide virtual keyboards.
2122 text: "Hello world!"
2123 activeFocusOnPress: false
2125 anchors.fill: parent
2127 if (!textEdit.activeFocus) {
2128 textEdit.forceActiveFocus();
2129 textEdit.openSoftwareInputPanel();
2131 textEdit.focus = false;
2134 onPressAndHold: textEdit.closeSoftwareInputPanel();
2139 void QQuickTextEdit::closeSoftwareInputPanel()
2142 qGuiApp->inputPanel()->hide();
2145 void QQuickTextEdit::focusInEvent(QFocusEvent *event)
2147 Q_D(const QQuickTextEdit);
2148 if (d->focusOnPress && !isReadOnly())
2149 openSoftwareInputPanel();
2150 QQuickImplicitSizeItem::focusInEvent(event);
2153 void QQuickTextEdit::q_canPasteChanged()
2155 Q_D(QQuickTextEdit);
2156 bool old = d->canPaste;
2157 d->canPaste = d->control->canPaste();
2158 bool changed = old!=d->canPaste || !d->canPasteValid;
2159 d->canPasteValid = true;
2161 emit canPasteChanged();
2165 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2167 Returns the section of text that is between the \a start and \a end positions.
2169 The returned text does not include any rich text formatting.
2172 QString QQuickTextEdit::getText(int start, int end) const
2174 Q_D(const QQuickTextEdit);
2175 start = qBound(0, start, d->document->characterCount() - 1);
2176 end = qBound(0, end, d->document->characterCount() - 1);
2177 QTextCursor cursor(d->document);
2178 cursor.setPosition(start, QTextCursor::MoveAnchor);
2179 cursor.setPosition(end, QTextCursor::KeepAnchor);
2180 return cursor.selectedText();
2184 \qmlmethod string QtQuick2::TextEdit::getFormattedText(int start, int end)
2186 Returns the section of text that is between the \a start and \a end positions.
2188 The returned text will be formatted according the \l textFormat property.
2191 QString QQuickTextEdit::getFormattedText(int start, int end) const
2193 Q_D(const QQuickTextEdit);
2195 start = qBound(0, start, d->document->characterCount() - 1);
2196 end = qBound(0, end, d->document->characterCount() - 1);
2198 QTextCursor cursor(d->document);
2199 cursor.setPosition(start, QTextCursor::MoveAnchor);
2200 cursor.setPosition(end, QTextCursor::KeepAnchor);
2203 #ifndef QT_NO_TEXTHTMLPARSER
2204 return cursor.selection().toHtml();
2206 return cursor.selection().toPlainText();
2209 return cursor.selection().toPlainText();
2214 \qmlmethod void QtQuick2::TextEdit::insert(int position, string text)
2216 Inserts \a text into the TextEdit at position.
2218 void QQuickTextEdit::insert(int position, const QString &text)
2220 Q_D(QQuickTextEdit);
2221 if (position < 0 || position >= d->document->characterCount())
2223 QTextCursor cursor(d->document);
2224 cursor.setPosition(position);
2225 d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text));
2227 #ifndef QT_NO_TEXTHTMLPARSER
2228 cursor.insertHtml(text);
2230 cursor.insertText(text);
2233 cursor.insertText(text);
2238 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2240 Removes the section of text that is between the \a start and \a end positions from the TextEdit.
2243 void QQuickTextEdit::remove(int start, int end)
2245 Q_D(QQuickTextEdit);
2246 start = qBound(0, start, d->document->characterCount() - 1);
2247 end = qBound(0, end, d->document->characterCount() - 1);
2248 QTextCursor cursor(d->document);
2249 cursor.setPosition(start, QTextCursor::MoveAnchor);
2250 cursor.setPosition(end, QTextCursor::KeepAnchor);
2251 cursor.removeSelectedText();