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);
277 \qmlproperty enumeration QtQuick2::TextEdit::textFormat
279 The way the text property should be displayed.
283 \o TextEdit.PlainText
287 The default is TextEdit.PlainText. If the text format is TextEdit.AutoText the text edit
288 will automatically determine whether the text should be treated as
289 rich text. This determination is made using Qt::mightBeRichText().
298 text: "<b>Hello</b> <i>World!</i>"
302 textFormat: TextEdit.RichText
303 text: "<b>Hello</b> <i>World!</i>"
307 textFormat: TextEdit.PlainText
308 text: "<b>Hello</b> <i>World!</i>"
312 \o \image declarative-textformat.png
315 QQuickTextEdit::TextFormat QQuickTextEdit::textFormat() const
317 Q_D(const QQuickTextEdit);
321 void QQuickTextEdit::setTextFormat(TextFormat format)
324 if (format == d->format)
327 bool wasRich = d->richText;
328 d->richText = format == RichText || (format == AutoText && (wasRich || Qt::mightBeRichText(text())));
330 #ifndef QT_NO_TEXTHTMLPARSER
331 if (wasRich && !d->richText) {
332 d->control->setPlainText(!d->textCached ? d->control->toHtml() : d->text);
334 } else if (!wasRich && d->richText) {
335 d->control->setHtml(!d->textCached ? d->control->toPlainText() : d->text);
337 d->useImageFallback = qmlEnableImageCache();
342 d->control->setAcceptRichText(d->format != PlainText);
343 emit textFormatChanged(d->format);
346 QFont QQuickTextEdit::font() const
348 Q_D(const QQuickTextEdit);
349 return d->sourceFont;
352 void QQuickTextEdit::setFont(const QFont &font)
355 if (d->sourceFont == font)
358 d->sourceFont = font;
359 QFont oldFont = d->font;
361 if (d->font.pointSizeF() != -1) {
363 qreal size = qRound(d->font.pointSizeF()*2.0);
364 d->font.setPointSizeF(size/2.0);
367 if (oldFont != d->font) {
368 d->document->setDefaultFont(d->font);
370 d->cursor->setHeight(QFontMetrics(d->font).height());
371 moveCursorDelegate();
375 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
377 emit fontChanged(d->sourceFont);
381 \qmlproperty color QtQuick2::TextEdit::color
386 // green text using hexadecimal notation
387 TextEdit { color: "#00FF00" }
391 // steelblue text using SVG color name
392 TextEdit { color: "steelblue" }
395 QColor QQuickTextEdit::color() const
397 Q_D(const QQuickTextEdit);
401 void QQuickTextEdit::setColor(const QColor &color)
404 if (d->color == color)
408 QPalette pal = d->control->palette();
409 pal.setColor(QPalette::Text, color);
410 d->control->setPalette(pal);
412 emit colorChanged(d->color);
416 \qmlproperty color QtQuick2::TextEdit::selectionColor
418 The text highlight color, used behind selections.
420 QColor QQuickTextEdit::selectionColor() const
422 Q_D(const QQuickTextEdit);
423 return d->selectionColor;
426 void QQuickTextEdit::setSelectionColor(const QColor &color)
429 if (d->selectionColor == color)
432 d->selectionColor = color;
433 QPalette pal = d->control->palette();
434 pal.setColor(QPalette::Highlight, color);
435 d->control->setPalette(pal);
437 emit selectionColorChanged(d->selectionColor);
441 \qmlproperty color QtQuick2::TextEdit::selectedTextColor
443 The selected text color, used in selections.
445 QColor QQuickTextEdit::selectedTextColor() const
447 Q_D(const QQuickTextEdit);
448 return d->selectedTextColor;
451 void QQuickTextEdit::setSelectedTextColor(const QColor &color)
454 if (d->selectedTextColor == color)
457 d->selectedTextColor = color;
458 QPalette pal = d->control->palette();
459 pal.setColor(QPalette::HighlightedText, color);
460 d->control->setPalette(pal);
462 emit selectedTextColorChanged(d->selectedTextColor);
466 \qmlproperty enumeration QtQuick2::TextEdit::horizontalAlignment
467 \qmlproperty enumeration QtQuick2::TextEdit::verticalAlignment
468 \qmlproperty enumeration QtQuick2::TextEdit::effectiveHorizontalAlignment
470 Sets the horizontal and vertical alignment of the text within the TextEdit item's
471 width and height. By default, the text alignment follows the natural alignment
472 of the text, for example text that is read from left to right will be aligned to
475 Valid values for \c horizontalAlignment are:
477 \o TextEdit.AlignLeft (default)
478 \o TextEdit.AlignRight
479 \o TextEdit.AlignHCenter
480 \o TextEdit.AlignJustify
483 Valid values for \c verticalAlignment are:
485 \o TextEdit.AlignTop (default)
486 \o TextEdit.AlignBottom
487 \o TextEdit.AlignVCenter
490 When using the attached property LayoutMirroring::enabled to mirror application
491 layouts, the horizontal alignment of text will also be mirrored. However, the property
492 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
493 of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
495 QQuickTextEdit::HAlignment QQuickTextEdit::hAlign() const
497 Q_D(const QQuickTextEdit);
501 void QQuickTextEdit::setHAlign(HAlignment align)
504 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
505 d->hAlignImplicit = false;
506 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
507 d->updateDefaultTextOption();
512 void QQuickTextEdit::resetHAlign()
515 d->hAlignImplicit = true;
516 if (d->determineHorizontalAlignment() && isComponentComplete()) {
517 d->updateDefaultTextOption();
522 QQuickTextEdit::HAlignment QQuickTextEdit::effectiveHAlign() const
524 Q_D(const QQuickTextEdit);
525 QQuickTextEdit::HAlignment effectiveAlignment = d->hAlign;
526 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
528 case QQuickTextEdit::AlignLeft:
529 effectiveAlignment = QQuickTextEdit::AlignRight;
531 case QQuickTextEdit::AlignRight:
532 effectiveAlignment = QQuickTextEdit::AlignLeft;
538 return effectiveAlignment;
541 bool QQuickTextEditPrivate::setHAlign(QQuickTextEdit::HAlignment alignment, bool forceAlign)
544 if (hAlign != alignment || forceAlign) {
545 QQuickTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
547 emit q->horizontalAlignmentChanged(alignment);
548 if (oldEffectiveHAlign != q->effectiveHAlign())
549 emit q->effectiveHorizontalAlignmentChanged();
555 bool QQuickTextEditPrivate::determineHorizontalAlignment()
558 if (hAlignImplicit && q->isComponentComplete()) {
560 if (document->isEmpty()) {
561 const QString preeditText = control->textCursor().block().layout()->preeditAreaText();
562 alignToRight = preeditText.isEmpty()
563 ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
564 : preeditText.isRightToLeft();
566 alignToRight = rightToLeftText;
568 return setHAlign(alignToRight ? QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft);
573 void QQuickTextEditPrivate::mirrorChange()
576 if (q->isComponentComplete()) {
577 if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) {
578 updateDefaultTextOption();
580 emit q->effectiveHorizontalAlignmentChanged();
585 QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const
587 Q_D(const QQuickTextEdit);
591 void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment)
594 if (alignment == d->vAlign)
596 d->vAlign = alignment;
597 d->updateDefaultTextOption();
599 moveCursorDelegate();
600 emit verticalAlignmentChanged(d->vAlign);
603 \qmlproperty enumeration QtQuick2::TextEdit::wrapMode
605 Set this property to wrap the text to the TextEdit item's width.
606 The text will only wrap if an explicit width has been set.
609 \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
610 \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
611 \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
612 \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.
615 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
617 QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode() const
619 Q_D(const QQuickTextEdit);
623 void QQuickTextEdit::setWrapMode(WrapMode mode)
626 if (mode == d->wrapMode)
629 d->updateDefaultTextOption();
631 emit wrapModeChanged();
635 \qmlproperty int QtQuick2::TextEdit::lineCount
637 Returns the total number of lines in the textEdit item.
639 int QQuickTextEdit::lineCount() const
641 Q_D(const QQuickTextEdit);
646 \qmlproperty int QtQuick2::TextEdit::length
648 Returns the total number of plain text characters in the TextEdit item.
650 As this number doesn't include any formatting markup it may not be the same as the
651 length of the string returned by the \l text property.
653 This property can be faster than querying the length the \l text property as it doesn't
654 require any copying or conversion of the TextEdit's internal string data.
657 int QQuickTextEdit::length() const
659 Q_D(const QQuickTextEdit);
660 // QTextDocument::characterCount() includes the terminating null character.
661 return qMax(0, d->document->characterCount() - 1);
665 \qmlproperty real QtQuick2::TextEdit::contentWidth
667 Returns the width of the text, including the width past the width
668 which is covered due to insufficient wrapping if \l wrapMode is set.
670 qreal QQuickTextEdit::contentWidth() const
672 Q_D(const QQuickTextEdit);
673 return d->contentSize.width();
677 \qmlproperty real QtQuick2::TextEdit::contentHeight
679 Returns the height of the text, including the height past the height
680 that is covered if the text does not fit within the set height.
682 qreal QQuickTextEdit::contentHeight() const
684 Q_D(const QQuickTextEdit);
685 return d->contentSize.height();
689 \qmlproperty url QtQuick2::TextEdit::baseUrl
691 This property specifies a base URL which is used to resolve relative URLs
694 By default is the url of the TextEdit element.
697 QUrl QQuickTextEdit::baseUrl() const
699 Q_D(const QQuickTextEdit);
700 if (d->baseUrl.isEmpty()) {
701 if (QDeclarativeContext *context = qmlContext(this))
702 const_cast<QQuickTextEditPrivate *>(d)->baseUrl = context->baseUrl();
707 void QQuickTextEdit::setBaseUrl(const QUrl &url)
710 if (baseUrl() != url) {
713 d->document->setBaseUrl(url, d->richText);
714 emit baseUrlChanged();
718 void QQuickTextEdit::resetBaseUrl()
720 if (QDeclarativeContext *context = qmlContext(this))
721 setBaseUrl(context->baseUrl());
727 \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position)
729 Returns the rectangle at the given \a position in the text. The x, y,
730 and height properties correspond to the cursor that would describe
733 QRectF QQuickTextEdit::positionToRectangle(int pos) const
735 Q_D(const QQuickTextEdit);
736 QTextCursor c(d->document);
738 return d->control->cursorRect(c).translated(0, d->yoff);
743 \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y)
745 Returns the text position closest to pixel position (\a x, \a y).
747 Position 0 is before the first character, position 1 is after the first character
748 but before the second, and so on until position \l {text}.length, which is after all characters.
750 int QQuickTextEdit::positionAt(int x, int y) const
752 Q_D(const QQuickTextEdit);
753 int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
754 QTextCursor cursor = d->control->textCursor();
755 if (r > cursor.position()) {
756 // The cursor position includes positions within the preedit text, but only positions in the
757 // same text block are offset so it is possible to get a position that is either part of the
758 // preedit or the next text block.
759 QTextLayout *layout = cursor.block().layout();
760 const int preeditLength = layout
761 ? layout->preeditAreaText().length()
763 if (preeditLength > 0
764 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
765 r = r > cursor.position() + preeditLength
774 \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
776 Moves the cursor to \a position and updates the selection according to the optional \a mode
777 parameter. (To only move the cursor, set the \l cursorPosition property.)
779 When this method is called it additionally sets either the
780 selectionStart or the selectionEnd (whichever was at the previous cursor position)
781 to the specified position. This allows you to easily extend and contract the selected
784 The selection mode specifies whether the selection is updated on a per character or a per word
785 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
788 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
789 the previous cursor position) to the specified position.
790 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
791 words between the specified position and the previous cursor position. Words partially in the
795 For example, take this sequence of calls:
799 moveCursorSelection(9, TextEdit.SelectCharacters)
800 moveCursorSelection(7, TextEdit.SelectCharacters)
803 This moves the cursor to position 5, extend the selection end from 5 to 9
804 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
805 selected (the 6th and 7th characters).
807 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
808 before or on position 5 and extend the selection end to a word boundary on or past position 9.
810 void QQuickTextEdit::moveCursorSelection(int pos)
812 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
814 QTextCursor cursor = d->control->textCursor();
815 if (cursor.position() == pos)
817 cursor.setPosition(pos, QTextCursor::KeepAnchor);
818 d->control->setTextCursor(cursor);
821 void QQuickTextEdit::moveCursorSelection(int pos, SelectionMode mode)
824 QTextCursor cursor = d->control->textCursor();
825 if (cursor.position() == pos)
827 if (mode == SelectCharacters) {
828 cursor.setPosition(pos, QTextCursor::KeepAnchor);
829 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
830 if (cursor.anchor() > cursor.position()) {
831 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
832 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
833 if (cursor.position() == cursor.anchor())
834 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
836 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
838 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
839 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
842 cursor.setPosition(pos, QTextCursor::KeepAnchor);
843 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
844 if (cursor.position() != pos)
845 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
846 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
847 if (cursor.anchor() < cursor.position()) {
848 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
849 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
851 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
852 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
853 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
854 if (cursor.position() != cursor.anchor()) {
855 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
856 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
860 cursor.setPosition(pos, QTextCursor::KeepAnchor);
861 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
862 if (cursor.position() != pos) {
863 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
864 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
867 d->control->setTextCursor(cursor);
871 \qmlproperty bool QtQuick2::TextEdit::cursorVisible
872 If true the text edit shows a cursor.
874 This property is set and unset when the text edit gets active focus, but it can also
875 be set directly (useful, for example, if a KeyProxy might forward keys to it).
877 bool QQuickTextEdit::isCursorVisible() const
879 Q_D(const QQuickTextEdit);
880 return d->cursorVisible;
883 void QQuickTextEdit::setCursorVisible(bool on)
886 if (d->cursorVisible == on)
888 d->cursorVisible = on;
889 QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
890 if (!on && !d->persistentSelection)
891 d->control->setCursorIsFocusIndicator(true);
892 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
893 emit cursorVisibleChanged(d->cursorVisible);
897 \qmlproperty int QtQuick2::TextEdit::cursorPosition
898 The position of the cursor in the TextEdit.
900 int QQuickTextEdit::cursorPosition() const
902 Q_D(const QQuickTextEdit);
903 return d->control->textCursor().position();
906 void QQuickTextEdit::setCursorPosition(int pos)
909 if (pos < 0 || pos >= d->document->characterCount()) // characterCount includes the terminating null.
911 QTextCursor cursor = d->control->textCursor();
912 if (cursor.position() == pos && cursor.anchor() == pos)
914 cursor.setPosition(pos);
915 d->control->setTextCursor(cursor);
919 \qmlproperty Component QtQuick2::TextEdit::cursorDelegate
920 The delegate for the cursor in the TextEdit.
922 If you set a cursorDelegate for a TextEdit, this delegate will be used for
923 drawing the cursor instead of the standard cursor. An instance of the
924 delegate will be created and managed by the text edit when a cursor is
925 needed, and the x and y properties of delegate instance will be set so as
926 to be one pixel before the top left of the current character.
928 Note that the root item of the delegate component must be a QDeclarativeItem or
929 QDeclarativeItem derived item.
931 QDeclarativeComponent* QQuickTextEdit::cursorDelegate() const
933 Q_D(const QQuickTextEdit);
934 return d->cursorComponent;
937 void QQuickTextEdit::setCursorDelegate(QDeclarativeComponent* c)
940 if (d->cursorComponent) {
942 d->control->setCursorWidth(-1);
948 d->cursorComponent = c;
949 if (c && c->isReady()) {
950 loadCursorDelegate();
953 connect(c, SIGNAL(statusChanged()),
954 this, SLOT(loadCursorDelegate()));
957 emit cursorDelegateChanged();
960 void QQuickTextEdit::loadCursorDelegate()
963 if (d->cursorComponent->isLoading())
965 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
966 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
967 d->cursor = qobject_cast<QQuickItem*>(object);
969 d->control->setCursorWidth(0);
971 QDeclarative_setParent_noEvent(d->cursor, this);
972 d->cursor->setParentItem(this);
973 d->cursor->setHeight(QFontMetrics(d->font).height());
974 moveCursorDelegate();
977 qmlInfo(this) << "Error loading cursor delegate.";
982 \qmlproperty int QtQuick2::TextEdit::selectionStart
984 The cursor position before the first character in the current selection.
986 This property is read-only. To change the selection, use select(start,end),
987 selectAll(), or selectWord().
989 \sa selectionEnd, cursorPosition, selectedText
991 int QQuickTextEdit::selectionStart() const
993 Q_D(const QQuickTextEdit);
994 return d->control->textCursor().selectionStart();
998 \qmlproperty int QtQuick2::TextEdit::selectionEnd
1000 The cursor position after the last character in the current selection.
1002 This property is read-only. To change the selection, use select(start,end),
1003 selectAll(), or selectWord().
1005 \sa selectionStart, cursorPosition, selectedText
1007 int QQuickTextEdit::selectionEnd() const
1009 Q_D(const QQuickTextEdit);
1010 return d->control->textCursor().selectionEnd();
1014 \qmlproperty string QtQuick2::TextEdit::selectedText
1016 This read-only property provides the text currently selected in the
1019 It is equivalent to the following snippet, but is faster and easier
1022 //myTextEdit is the id of the TextEdit
1023 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
1024 myTextEdit.selectionEnd);
1027 QString QQuickTextEdit::selectedText() const
1029 Q_D(const QQuickTextEdit);
1030 return d->control->textCursor().selectedText();
1034 \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress
1036 Whether the TextEdit should gain active focus on a mouse press. By default this is
1039 bool QQuickTextEdit::focusOnPress() const
1041 Q_D(const QQuickTextEdit);
1042 return d->focusOnPress;
1045 void QQuickTextEdit::setFocusOnPress(bool on)
1047 Q_D(QQuickTextEdit);
1048 if (d->focusOnPress == on)
1050 d->focusOnPress = on;
1051 emit activeFocusOnPressChanged(d->focusOnPress);
1055 \qmlproperty bool QtQuick2::TextEdit::persistentSelection
1057 Whether the TextEdit should keep the selection visible when it loses active focus to another
1058 item in the scene. By default this is set to true;
1060 bool QQuickTextEdit::persistentSelection() const
1062 Q_D(const QQuickTextEdit);
1063 return d->persistentSelection;
1066 void QQuickTextEdit::setPersistentSelection(bool on)
1068 Q_D(QQuickTextEdit);
1069 if (d->persistentSelection == on)
1071 d->persistentSelection = on;
1072 emit persistentSelectionChanged(d->persistentSelection);
1076 \qmlproperty real QtQuick2::TextEdit::textMargin
1078 The margin, in pixels, around the text in the TextEdit.
1080 qreal QQuickTextEdit::textMargin() const
1082 Q_D(const QQuickTextEdit);
1083 return d->textMargin;
1086 void QQuickTextEdit::setTextMargin(qreal margin)
1088 Q_D(QQuickTextEdit);
1089 if (d->textMargin == margin)
1091 d->textMargin = margin;
1092 d->document->setDocumentMargin(d->textMargin);
1093 emit textMarginChanged(d->textMargin);
1097 \qmlproperty enumeration QtQuick2::TextEdit::inputMethodHints
1099 Provides hints to the input method about the expected content of the text edit and how it
1102 The value is a bit-wise combination of flags or Qt.ImhNone if no hints are set.
1104 Flags that alter behaviour are:
1107 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1108 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1109 in any persistent storage like predictive user dictionary.
1110 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1111 when a sentence ends.
1112 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1113 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1114 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1115 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1117 \o Qt.ImhDate - The text editor functions as a date field.
1118 \o Qt.ImhTime - The text editor functions as a time field.
1121 Flags that restrict input (exclusive flags) are:
1124 \o Qt.ImhDigitsOnly - Only digits are allowed.
1125 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1126 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1127 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1128 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1129 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1130 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1136 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1140 void QQuickTextEdit::geometryChanged(const QRectF &newGeometry,
1141 const QRectF &oldGeometry)
1143 if (newGeometry.width() != oldGeometry.width())
1145 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1149 Ensures any delayed caching or data loading the class
1150 needs to performed is complete.
1152 void QQuickTextEdit::componentComplete()
1154 Q_D(QQuickTextEdit);
1155 QQuickImplicitSizeItem::componentComplete();
1157 d->document->setBaseUrl(baseUrl(), d->richText);
1159 d->useImageFallback = qmlEnableImageCache();
1162 d->determineHorizontalAlignment();
1163 d->updateDefaultTextOption();
1170 \qmlproperty bool QtQuick2::TextEdit::selectByMouse
1174 If true, the user can use the mouse to select text in some
1175 platform-specific way. Note that for some platforms this may
1176 not be an appropriate interaction (eg. may conflict with how
1177 the text needs to behave inside a Flickable.
1179 bool QQuickTextEdit::selectByMouse() const
1181 Q_D(const QQuickTextEdit);
1182 return d->selectByMouse;
1185 void QQuickTextEdit::setSelectByMouse(bool on)
1187 Q_D(QQuickTextEdit);
1188 if (d->selectByMouse != on) {
1189 d->selectByMouse = on;
1190 setKeepMouseGrab(on);
1192 setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1194 setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1195 emit selectByMouseChanged(on);
1200 \qmlproperty enum QtQuick2::TextEdit::mouseSelectionMode
1202 Specifies how text should be selected using a mouse.
1205 \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1206 \o TextEdit.SelectWords - The selection is updated with whole words.
1209 This property only applies when \l selectByMouse is true.
1211 QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode() const
1213 Q_D(const QQuickTextEdit);
1214 return d->mouseSelectionMode;
1217 void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode)
1219 Q_D(QQuickTextEdit);
1220 if (d->mouseSelectionMode != mode) {
1221 d->mouseSelectionMode = mode;
1222 d->control->setWordSelectionEnabled(mode == SelectWords);
1223 emit mouseSelectionModeChanged(mode);
1228 \qmlproperty bool QtQuick2::TextEdit::readOnly
1230 Whether the user can interact with the TextEdit item. If this
1231 property is set to true the text cannot be edited by user interaction.
1233 By default this property is false.
1235 void QQuickTextEdit::setReadOnly(bool r)
1237 Q_D(QQuickTextEdit);
1238 if (r == isReadOnly())
1241 setFlag(QQuickItem::ItemAcceptsInputMethod, !r);
1242 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1243 if (d->selectByMouse)
1244 flags = flags | Qt::TextSelectableByMouse;
1246 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1247 d->control->setTextInteractionFlags(flags);
1249 d->control->moveCursor(QTextCursor::End);
1251 updateInputMethod(Qt::ImEnabled);
1252 q_canPasteChanged();
1253 emit readOnlyChanged(r);
1256 bool QQuickTextEdit::isReadOnly() const
1258 Q_D(const QQuickTextEdit);
1259 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1263 Sets how the text edit should interact with user input to the given
1266 void QQuickTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1268 Q_D(QQuickTextEdit);
1269 d->control->setTextInteractionFlags(flags);
1273 Returns the flags specifying how the text edit should interact
1276 Qt::TextInteractionFlags QQuickTextEdit::textInteractionFlags() const
1278 Q_D(const QQuickTextEdit);
1279 return d->control->textInteractionFlags();
1283 \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle
1285 The rectangle where the standard text cursor is rendered
1286 within the text edit. Read-only.
1288 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
1289 automatically when it changes. The width of the delegate is unaffected by changes in the
1292 QRect QQuickTextEdit::cursorRectangle() const
1294 Q_D(const QQuickTextEdit);
1295 return d->control->cursorRect().toRect().translated(0,d->yoff);
1298 bool QQuickTextEdit::event(QEvent *event)
1300 Q_D(QQuickTextEdit);
1301 if (event->type() == QEvent::ShortcutOverride) {
1302 d->control->processEvent(event, QPointF(0, -d->yoff));
1303 return event->isAccepted();
1305 return QQuickImplicitSizeItem::event(event);
1310 Handles the given key \a event.
1312 void QQuickTextEdit::keyPressEvent(QKeyEvent *event)
1314 Q_D(QQuickTextEdit);
1315 d->control->processEvent(event, QPointF(0, -d->yoff));
1316 if (!event->isAccepted())
1317 QQuickImplicitSizeItem::keyPressEvent(event);
1322 Handles the given key \a event.
1324 void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event)
1326 Q_D(QQuickTextEdit);
1327 d->control->processEvent(event, QPointF(0, -d->yoff));
1328 if (!event->isAccepted())
1329 QQuickImplicitSizeItem::keyReleaseEvent(event);
1333 \qmlmethod void QtQuick2::TextEdit::deselect()
1335 Removes active text selection.
1337 void QQuickTextEdit::deselect()
1339 Q_D(QQuickTextEdit);
1340 QTextCursor c = d->control->textCursor();
1342 d->control->setTextCursor(c);
1346 \qmlmethod void QtQuick2::TextEdit::selectAll()
1348 Causes all text to be selected.
1350 void QQuickTextEdit::selectAll()
1352 Q_D(QQuickTextEdit);
1353 d->control->selectAll();
1357 \qmlmethod void QtQuick2::TextEdit::selectWord()
1359 Causes the word closest to the current cursor position to be selected.
1361 void QQuickTextEdit::selectWord()
1363 Q_D(QQuickTextEdit);
1364 QTextCursor c = d->control->textCursor();
1365 c.select(QTextCursor::WordUnderCursor);
1366 d->control->setTextCursor(c);
1370 \qmlmethod void QtQuick2::TextEdit::select(int start, int end)
1372 Causes the text from \a start to \a end to be selected.
1374 If either start or end is out of range, the selection is not changed.
1376 After calling this, selectionStart will become the lesser
1377 and selectionEnd will become the greater (regardless of the order passed
1380 \sa selectionStart, selectionEnd
1382 void QQuickTextEdit::select(int start, int end)
1384 Q_D(QQuickTextEdit);
1385 if (start < 0 || end < 0 || start >= d->document->characterCount() || end >= d->document->characterCount())
1387 QTextCursor cursor = d->control->textCursor();
1388 cursor.beginEditBlock();
1389 cursor.setPosition(start, QTextCursor::MoveAnchor);
1390 cursor.setPosition(end, QTextCursor::KeepAnchor);
1391 cursor.endEditBlock();
1392 d->control->setTextCursor(cursor);
1395 updateSelectionMarkers();
1399 \qmlmethod void QtQuick2::TextEdit::isRightToLeft(int start, int end)
1401 Returns true if the natural reading direction of the editor text
1402 found between positions \a start and \a end is right to left.
1404 bool QQuickTextEdit::isRightToLeft(int start, int end)
1407 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1410 return getText(start, end).isRightToLeft();
1414 #ifndef QT_NO_CLIPBOARD
1416 \qmlmethod QtQuick2::TextEdit::cut()
1418 Moves the currently selected text to the system clipboard.
1420 void QQuickTextEdit::cut()
1422 Q_D(QQuickTextEdit);
1427 \qmlmethod QtQuick2::TextEdit::copy()
1429 Copies the currently selected text to the system clipboard.
1431 void QQuickTextEdit::copy()
1433 Q_D(QQuickTextEdit);
1438 \qmlmethod QtQuick2::TextEdit::paste()
1440 Replaces the currently selected text by the contents of the system clipboard.
1442 void QQuickTextEdit::paste()
1444 Q_D(QQuickTextEdit);
1445 d->control->paste();
1447 #endif // QT_NO_CLIPBOARD
1451 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1452 current selection, and updates the selection start to the current cursor
1456 void QQuickTextEdit::undo()
1458 Q_D(QQuickTextEdit);
1463 Redoes the last operation if redo is \l {canRedo}{available}.
1466 void QQuickTextEdit::redo()
1468 Q_D(QQuickTextEdit);
1474 Handles the given mouse \a event.
1476 void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
1478 Q_D(QQuickTextEdit);
1479 if (d->focusOnPress){
1480 bool hadActiveFocus = hasActiveFocus();
1482 // re-open input panel on press if already focused
1483 if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
1484 openSoftwareInputPanel();
1486 d->control->processEvent(event, QPointF(0, -d->yoff));
1487 if (!event->isAccepted())
1488 QQuickImplicitSizeItem::mousePressEvent(event);
1493 Handles the given mouse \a event.
1495 void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
1497 Q_D(QQuickTextEdit);
1498 d->control->processEvent(event, QPointF(0, -d->yoff));
1500 if (!event->isAccepted())
1501 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1506 Handles the given mouse \a event.
1508 void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
1510 Q_D(QQuickTextEdit);
1511 d->control->processEvent(event, QPointF(0, -d->yoff));
1512 if (!event->isAccepted())
1513 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1518 Handles the given mouse \a event.
1520 void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
1522 Q_D(QQuickTextEdit);
1523 d->control->processEvent(event, QPointF(0, -d->yoff));
1524 if (!event->isAccepted())
1525 QQuickImplicitSizeItem::mouseMoveEvent(event);
1530 Handles the given input method \a event.
1532 void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
1534 Q_D(QQuickTextEdit);
1535 const bool wasComposing = isInputMethodComposing();
1536 d->control->processEvent(event, QPointF(0, -d->yoff));
1537 if (wasComposing != isInputMethodComposing())
1538 emit inputMethodComposingChanged();
1541 void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1543 if (change == ItemActiveFocusHasChanged) {
1544 setCursorVisible(value.boolValue); // ### refactor: focus handling && d->canvas && d->canvas->hasFocus());
1546 if (value.boolValue) {
1547 q_updateAlignment();
1548 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1549 this, SLOT(q_updateAlignment()));
1551 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1552 this, SLOT(q_updateAlignment()));
1555 QQuickItem::itemChange(change, value);
1560 Returns the value of the given \a property.
1562 QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1564 Q_D(const QQuickTextEdit);
1569 v = (bool)(flags() & ItemAcceptsInputMethod);
1572 v = (int)inputMethodHints();
1575 v = d->control->inputMethodQuery(property);
1582 void QQuickTextEdit::updateImageCache(const QRectF &)
1584 Q_D(QQuickTextEdit);
1586 // Do we really need the image cache?
1587 if (!d->richText || !d->useImageFallback) {
1588 if (!d->pixmapCache.isNull())
1589 d->pixmapCache = QPixmap();
1593 if (width() != d->pixmapCache.width() || height() != d->pixmapCache.height())
1594 d->pixmapCache = QPixmap(width(), height());
1596 if (d->pixmapCache.isNull())
1599 // ### Use supplied rect, clear area and update only this part (for cursor updates)
1600 QRectF bounds = QRectF(0, 0, width(), height());
1601 d->pixmapCache.fill(Qt::transparent);
1603 QPainter painter(&d->pixmapCache);
1605 painter.setRenderHint(QPainter::TextAntialiasing);
1606 painter.translate(0, d->yoff);
1608 d->control->drawContents(&painter, bounds);
1613 void QQuickTextEdit::triggerPreprocess()
1615 Q_D(QQuickTextEdit);
1616 if (d->updateType == QQuickTextEditPrivate::UpdateNone)
1617 d->updateType = QQuickTextEditPrivate::UpdateOnlyPreprocess;
1621 QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1623 Q_UNUSED(updatePaintNodeData);
1624 Q_D(QQuickTextEdit);
1626 if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode && oldNode != 0) {
1627 // Update done in preprocess() in the nodes
1628 d->updateType = QQuickTextEditPrivate::UpdateNone;
1632 d->updateType = QQuickTextEditPrivate::UpdateNone;
1634 QSGNode *currentNode = oldNode;
1635 if (d->richText && d->useImageFallback) {
1636 QSGImageNode *node = 0;
1637 if (oldNode == 0 || d->nodeType != QQuickTextEditPrivate::NodeIsTexture) {
1639 node = QQuickItemPrivate::get(this)->sceneGraphContext()->createImageNode();
1640 d->texture = new QSGPlainTexture();
1641 d->nodeType = QQuickTextEditPrivate::NodeIsTexture;
1644 node = static_cast<QSGImageNode *>(oldNode);
1647 qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->pixmapCache.toImage());
1648 node->setTexture(0);
1649 node->setTexture(d->texture);
1651 node->setTargetRect(QRectF(0, 0, d->pixmapCache.width(), d->pixmapCache.height()));
1652 node->setSourceRect(QRectF(0, 0, 1, 1));
1653 node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
1654 node->setVerticalWrapMode(QSGTexture::ClampToEdge);
1655 node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that..
1658 } else if (oldNode == 0 || d->documentDirty) {
1659 d->documentDirty = false;
1661 #if defined(Q_OS_MAC)
1662 // Make sure document is relayouted in the paint node on Mac
1663 // to avoid crashes due to the font engines created in the
1665 d->document->markContentsDirty(0, d->document->characterCount());
1668 QQuickTextNode *node = 0;
1669 if (oldNode == 0 || d->nodeType != QQuickTextEditPrivate::NodeIsText) {
1671 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1672 d->nodeType = QQuickTextEditPrivate::NodeIsText;
1675 node = static_cast<QQuickTextNode *>(oldNode);
1678 node->deleteContent();
1679 node->setMatrix(QMatrix4x4());
1681 QRectF bounds = boundingRect();
1683 QColor selectionColor = d->control->palette().color(QPalette::Highlight);
1684 QColor selectedTextColor = d->control->palette().color(QPalette::HighlightedText);
1685 node->addTextDocument(bounds.topLeft(), d->document, d->color, QQuickText::Normal, QColor(),
1686 selectionColor, selectedTextColor, selectionStart(),
1687 selectionEnd() - 1); // selectionEnd() returns first char after
1690 #if defined(Q_OS_MAC)
1691 // We also need to make sure the document layout is redone when
1692 // control is returned to the main thread, as all the font engines
1693 // are now owned by the rendering thread
1694 d->document->markContentsDirty(0, d->document->characterCount());
1698 if (d->nodeType == QQuickTextEditPrivate::NodeIsText && d->cursorComponent == 0 && !isReadOnly()) {
1699 QQuickTextNode *node = static_cast<QQuickTextNode *>(currentNode);
1701 QColor color = (!d->cursorVisible || !d->control->cursorOn())
1702 ? QColor(0, 0, 0, 0)
1705 if (node->cursorNode() == 0) {
1706 node->setCursor(cursorRectangle(), color);
1708 node->cursorNode()->setRect(cursorRectangle());
1709 node->cursorNode()->setColor(color);
1718 \qmlproperty bool QtQuick2::TextEdit::smooth
1720 This property holds whether the text is smoothly scaled or transformed.
1722 Smooth filtering gives better visual quality, but is slower. If
1723 the item is displayed at its natural size, this property has no visual or
1726 \note Generally scaling artifacts are only visible if the item is stationary on
1727 the screen. A common pattern when animating an item is to disable smooth
1728 filtering at the beginning of the animation and reenable it at the conclusion.
1732 \qmlproperty bool QtQuick2::TextEdit::canPaste
1734 Returns true if the TextEdit is writable and the content of the clipboard is
1735 suitable for pasting into the TextEdit.
1737 bool QQuickTextEdit::canPaste() const
1739 Q_D(const QQuickTextEdit);
1740 if (!d->canPasteValid) {
1741 const_cast<QQuickTextEditPrivate *>(d)->canPaste = d->control->canPaste();
1742 const_cast<QQuickTextEditPrivate *>(d)->canPasteValid = true;
1748 \qmlproperty bool QtQuick2::TextEdit::canUndo
1750 Returns true if the TextEdit is writable and there are previous operations
1754 bool QQuickTextEdit::canUndo() const
1756 Q_D(const QQuickTextEdit);
1757 return d->document->isUndoAvailable();
1761 \qmlproperty bool QtQuick2::TextEdit::canRedo
1763 Returns true if the TextEdit is writable and there are \l {undo}{undone}
1764 operations that can be redone.
1767 bool QQuickTextEdit::canRedo() const
1769 Q_D(const QQuickTextEdit);
1770 return d->document->isRedoAvailable();
1774 \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1777 This property holds whether the TextEdit has partial text input from an
1780 While it is composing an input method may rely on mouse or key events from
1781 the TextEdit to edit or commit the partial text. This property can be used
1782 to determine when to disable events handlers that may interfere with the
1783 correct operation of an input method.
1785 bool QQuickTextEdit::isInputMethodComposing() const
1787 Q_D(const QQuickTextEdit);
1788 if (QTextLayout *layout = d->control->textCursor().block().layout())
1789 return layout->preeditAreaText().length() > 0;
1793 void QQuickTextEditPrivate::init()
1795 Q_Q(QQuickTextEdit);
1797 q->setSmooth(smooth);
1798 q->setAcceptedMouseButtons(Qt::LeftButton);
1799 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1800 q->setFlag(QQuickItem::ItemHasContents);
1802 document = new QQuickTextDocumentWithImageResources(q);
1804 control = new QQuickTextControl(document, q);
1805 control->setView(q);
1806 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1807 control->setAcceptRichText(false);
1808 control->setCursorIsFocusIndicator(true);
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 QSize size(newWidth, newHeight);
1969 if (d->contentSize != size) {
1970 d->contentSize = size;
1971 emit contentSizeChanged();
1979 void QQuickTextEdit::updateDocument()
1981 Q_D(QQuickTextEdit);
1982 d->documentDirty = true;
1984 if (isComponentComplete()) {
1986 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1991 void QQuickTextEdit::updateCursor()
1993 Q_D(QQuickTextEdit);
1994 if (isComponentComplete()) {
1995 updateImageCache(d->control->cursorRect());
1996 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
2001 void QQuickTextEdit::q_updateAlignment()
2003 Q_D(QQuickTextEdit);
2004 if (d->determineHorizontalAlignment()) {
2005 d->updateDefaultTextOption();
2006 moveCursorDelegate();
2010 void QQuickTextEdit::updateTotalLines()
2012 Q_D(QQuickTextEdit);
2016 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
2017 QTextLayout *layout = it.layout();
2020 subLines += layout->lineCount()-1;
2023 int newTotalLines = d->document->lineCount() + subLines;
2024 if (d->lineCount != newTotalLines) {
2025 d->lineCount = newTotalLines;
2026 emit lineCountChanged();
2030 void QQuickTextEditPrivate::updateDefaultTextOption()
2032 Q_Q(QQuickTextEdit);
2033 QTextOption opt = document->defaultTextOption();
2034 int oldAlignment = opt.alignment();
2036 QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
2037 if (rightToLeftText) {
2038 if (horizontalAlignment == QQuickTextEdit::AlignLeft)
2039 horizontalAlignment = QQuickTextEdit::AlignRight;
2040 else if (horizontalAlignment == QQuickTextEdit::AlignRight)
2041 horizontalAlignment = QQuickTextEdit::AlignLeft;
2043 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
2045 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
2046 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
2048 bool oldUseDesignMetrics = opt.useDesignMetrics();
2049 bool useDesignMetrics = !qmlDisableDistanceField();
2050 opt.setUseDesignMetrics(useDesignMetrics);
2052 if (oldWrapMode == opt.wrapMode()
2053 && oldAlignment == opt.alignment()
2054 && oldUseDesignMetrics == useDesignMetrics) {
2057 document->setDefaultTextOption(opt);
2063 \qmlmethod void QtQuick2::TextEdit::openSoftwareInputPanel()
2065 Opens software input panels like virtual keyboards for typing, useful for
2066 customizing when you want the input keyboard to be shown and hidden in
2069 By default the opening of input panels follows the platform style. Input panels are
2070 always closed if no editor has active focus.
2072 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2073 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2074 the behavior you want.
2076 Only relevant on platforms, which provide virtual keyboards.
2082 text: "Hello world!"
2083 activeFocusOnPress: false
2085 anchors.fill: parent
2087 if (!textEdit.activeFocus) {
2088 textEdit.forceActiveFocus();
2089 textEdit.openSoftwareInputPanel();
2091 textEdit.focus = false;
2094 onPressAndHold: textEdit.closeSoftwareInputPanel();
2099 void QQuickTextEdit::openSoftwareInputPanel()
2102 qGuiApp->inputMethod()->show();
2106 \qmlmethod void QtQuick2::TextEdit::closeSoftwareInputPanel()
2108 Closes a software input panel like a virtual keyboard shown on the screen, useful
2109 for customizing when you want the input keyboard to be shown and hidden in
2112 By default the opening of input panels follows the platform style. Input panels are
2113 always closed if no editor has active focus.
2115 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2116 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2117 the behavior you want.
2119 Only relevant on platforms, which provide virtual keyboards.
2125 text: "Hello world!"
2126 activeFocusOnPress: false
2128 anchors.fill: parent
2130 if (!textEdit.activeFocus) {
2131 textEdit.forceActiveFocus();
2132 textEdit.openSoftwareInputPanel();
2134 textEdit.focus = false;
2137 onPressAndHold: textEdit.closeSoftwareInputPanel();
2142 void QQuickTextEdit::closeSoftwareInputPanel()
2145 qGuiApp->inputMethod()->hide();
2148 void QQuickTextEdit::focusInEvent(QFocusEvent *event)
2150 Q_D(const QQuickTextEdit);
2151 if (d->focusOnPress && !isReadOnly())
2152 openSoftwareInputPanel();
2153 QQuickImplicitSizeItem::focusInEvent(event);
2156 void QQuickTextEdit::q_canPasteChanged()
2158 Q_D(QQuickTextEdit);
2159 bool old = d->canPaste;
2160 d->canPaste = d->control->canPaste();
2161 bool changed = old!=d->canPaste || !d->canPasteValid;
2162 d->canPasteValid = true;
2164 emit canPasteChanged();
2168 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2170 Returns the section of text that is between the \a start and \a end positions.
2172 The returned text does not include any rich text formatting.
2175 QString QQuickTextEdit::getText(int start, int end) const
2177 Q_D(const QQuickTextEdit);
2178 start = qBound(0, start, d->document->characterCount() - 1);
2179 end = qBound(0, end, d->document->characterCount() - 1);
2180 QTextCursor cursor(d->document);
2181 cursor.setPosition(start, QTextCursor::MoveAnchor);
2182 cursor.setPosition(end, QTextCursor::KeepAnchor);
2183 return cursor.selectedText();
2187 \qmlmethod string QtQuick2::TextEdit::getFormattedText(int start, int end)
2189 Returns the section of text that is between the \a start and \a end positions.
2191 The returned text will be formatted according the \l textFormat property.
2194 QString QQuickTextEdit::getFormattedText(int start, int end) const
2196 Q_D(const QQuickTextEdit);
2198 start = qBound(0, start, d->document->characterCount() - 1);
2199 end = qBound(0, end, d->document->characterCount() - 1);
2201 QTextCursor cursor(d->document);
2202 cursor.setPosition(start, QTextCursor::MoveAnchor);
2203 cursor.setPosition(end, QTextCursor::KeepAnchor);
2206 #ifndef QT_NO_TEXTHTMLPARSER
2207 return cursor.selection().toHtml();
2209 return cursor.selection().toPlainText();
2212 return cursor.selection().toPlainText();
2217 \qmlmethod void QtQuick2::TextEdit::insert(int position, string text)
2219 Inserts \a text into the TextEdit at position.
2221 void QQuickTextEdit::insert(int position, const QString &text)
2223 Q_D(QQuickTextEdit);
2224 if (position < 0 || position >= d->document->characterCount())
2226 QTextCursor cursor(d->document);
2227 cursor.setPosition(position);
2228 d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text));
2230 #ifndef QT_NO_TEXTHTMLPARSER
2231 cursor.insertHtml(text);
2233 cursor.insertText(text);
2236 cursor.insertText(text);
2241 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2243 Removes the section of text that is between the \a start and \a end positions from the TextEdit.
2246 void QQuickTextEdit::remove(int start, int end)
2248 Q_D(QQuickTextEdit);
2249 start = qBound(0, start, d->document->characterCount() - 1);
2250 end = qBound(0, end, d->document->characterCount() - 1);
2251 QTextCursor cursor(d->document);
2252 cursor.setPosition(start, QTextCursor::MoveAnchor);
2253 cursor.setPosition(end, QTextCursor::KeepAnchor);
2254 cursor.removeSelectedText();