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