1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktextedit_p.h"
43 #include "qquicktextedit_p_p.h"
44 #include "qquicktextcontrol_p.h"
45 #include "qquicktext_p_p.h"
46 #include "qquickevents_p_p.h"
47 #include "qquickcanvas.h"
48 #include "qquicktextnode_p.h"
49 #include <QtQuick/qsgsimplerectnode.h>
51 #include <QtQml/qqmlinfo.h>
52 #include <QtGui/qguiapplication.h>
53 #include <QtGui/qevent.h>
54 #include <QtGui/qpainter.h>
55 #include <QtGui/qtextobject.h>
56 #include <QtCore/qmath.h>
58 #include <private/qqmlglobal_p.h>
59 #include <private/qqmlproperty_p.h>
60 #include <private/qtextengine_p.h>
61 #include <private/qsgadaptationlayer_p.h>
66 \qmlclass TextEdit QQuickTextEdit
67 \inqmlmodule QtQuick 2
68 \ingroup qml-basic-visual-elements
69 \brief The TextEdit item displays multiple lines of editable formatted text.
72 The TextEdit item displays a block of editable, formatted text.
74 It can display both plain and rich text. For example:
79 text: "<b>Hello</b> <i>World!</i>"
80 font.family: "Helvetica"
87 \image declarative-textedit.gif
89 Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
91 Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
92 to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
94 \snippet snippets/declarative/texteditor.qml 0
96 A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible
97 scrollbar, or a scrollbar that fades in to show location, etc.
99 Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
100 be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
101 from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
103 You can translate between cursor positions (characters from the start of the document) and pixel
104 points using positionAt() and positionToRectangle().
106 \sa Text, TextInput, {declarative/text/textselection}{Text Selection example}
110 \qmlsignal QtQuick2::TextEdit::onLinkActivated(string link)
112 This handler is called when the user clicks on a link embedded in the text.
113 The link must be in rich text or HTML format and the
114 \a link string provides access to the particular link.
116 QQuickTextEdit::QQuickTextEdit(QQuickItem *parent)
117 : QQuickImplicitSizeItem(*(new QQuickTextEditPrivate), parent)
123 QString QQuickTextEdit::text() const
125 Q_D(const QQuickTextEdit);
126 if (!d->textCached) {
127 QQuickTextEditPrivate *d = const_cast<QQuickTextEditPrivate *>(d_func());
128 #ifndef QT_NO_TEXTHTMLPARSER
130 d->text = d->control->toHtml();
133 d->text = d->control->toPlainText();
134 d->textCached = true;
140 \qmlproperty string QtQuick2::TextEdit::font.family
142 Sets the family name of the font.
144 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
145 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
146 If the family isn't available a family will be set using the font matching algorithm.
150 \qmlproperty bool QtQuick2::TextEdit::font.bold
152 Sets whether the font weight is bold.
156 \qmlproperty enumeration QtQuick2::TextEdit::font.weight
158 Sets the font's weight.
160 The weight can be one of:
163 \o Font.Normal - the default
170 TextEdit { text: "Hello"; font.weight: Font.DemiBold }
175 \qmlproperty bool QtQuick2::TextEdit::font.italic
177 Sets whether the font has an italic style.
181 \qmlproperty bool QtQuick2::TextEdit::font.underline
183 Sets whether the text is underlined.
187 \qmlproperty bool QtQuick2::TextEdit::font.strikeout
189 Sets whether the font has a strikeout style.
193 \qmlproperty real QtQuick2::TextEdit::font.pointSize
195 Sets the font size in points. The point size must be greater than zero.
199 \qmlproperty int QtQuick2::TextEdit::font.pixelSize
201 Sets the font size in pixels.
203 Using this function makes the font device dependent. Use
204 \l{TextEdit::font.pointSize} to set the size of the font in a
205 device independent manner.
209 \qmlproperty real QtQuick2::TextEdit::font.letterSpacing
211 Sets the letter spacing for the font.
213 Letter spacing changes the default spacing between individual letters in the font.
214 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
218 \qmlproperty real QtQuick2::TextEdit::font.wordSpacing
220 Sets the word spacing for the font.
222 Word spacing changes the default spacing between individual words.
223 A positive value increases the word spacing by a corresponding amount of pixels,
224 while a negative value decreases the inter-word spacing accordingly.
228 \qmlproperty enumeration QtQuick2::TextEdit::font.capitalization
230 Sets the capitalization for the text.
233 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
234 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
235 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
236 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
237 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
241 TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
246 \qmlproperty string QtQuick2::TextEdit::text
248 The text to display. If the text format is AutoText the text edit will
249 automatically determine whether the text should be treated as
250 rich text. This determination is made using Qt::mightBeRichText().
252 void QQuickTextEdit::setText(const QString &text)
255 if (QQuickTextEdit::text() == text)
258 d->document->clearResources();
259 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
261 #ifndef QT_NO_TEXTHTMLPARSER
262 d->control->setHtml(text);
264 d->control->setPlainText(text);
267 d->control->setPlainText(text);
272 \qmlproperty enumeration QtQuick2::TextEdit::textFormat
274 The way the text property should be displayed.
278 \o TextEdit.PlainText
282 The default is TextEdit.PlainText. If the text format is TextEdit.AutoText the text edit
283 will automatically determine whether the text should be treated as
284 rich text. This determination is made using Qt::mightBeRichText().
293 text: "<b>Hello</b> <i>World!</i>"
297 textFormat: TextEdit.RichText
298 text: "<b>Hello</b> <i>World!</i>"
302 textFormat: TextEdit.PlainText
303 text: "<b>Hello</b> <i>World!</i>"
307 \o \image declarative-textformat.png
310 QQuickTextEdit::TextFormat QQuickTextEdit::textFormat() const
312 Q_D(const QQuickTextEdit);
316 void QQuickTextEdit::setTextFormat(TextFormat format)
319 if (format == d->format)
322 bool wasRich = d->richText;
323 d->richText = format == RichText || (format == AutoText && (wasRich || Qt::mightBeRichText(text())));
325 #ifndef QT_NO_TEXTHTMLPARSER
326 if (wasRich && !d->richText) {
327 d->control->setPlainText(!d->textCached ? d->control->toHtml() : d->text);
329 } else if (!wasRich && d->richText) {
330 d->control->setHtml(!d->textCached ? d->control->toPlainText() : d->text);
336 d->control->setAcceptRichText(d->format != PlainText);
337 emit textFormatChanged(d->format);
340 QFont QQuickTextEdit::font() const
342 Q_D(const QQuickTextEdit);
343 return d->sourceFont;
346 void QQuickTextEdit::setFont(const QFont &font)
349 if (d->sourceFont == font)
352 d->sourceFont = font;
353 QFont oldFont = d->font;
355 if (d->font.pointSizeF() != -1) {
357 qreal size = qRound(d->font.pointSizeF()*2.0);
358 d->font.setPointSizeF(size/2.0);
361 if (oldFont != d->font) {
362 d->document->setDefaultFont(d->font);
364 d->cursor->setHeight(QFontMetrics(d->font).height());
365 moveCursorDelegate();
369 updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
371 emit fontChanged(d->sourceFont);
375 \qmlproperty color QtQuick2::TextEdit::color
380 // green text using hexadecimal notation
381 TextEdit { color: "#00FF00" }
385 // steelblue text using SVG color name
386 TextEdit { color: "steelblue" }
389 QColor QQuickTextEdit::color() const
391 Q_D(const QQuickTextEdit);
395 void QQuickTextEdit::setColor(const QColor &color)
398 if (d->color == color)
402 QPalette pal = d->control->palette();
403 pal.setColor(QPalette::Text, color);
404 d->control->setPalette(pal);
406 emit colorChanged(d->color);
410 \qmlproperty color QtQuick2::TextEdit::selectionColor
412 The text highlight color, used behind selections.
414 QColor QQuickTextEdit::selectionColor() const
416 Q_D(const QQuickTextEdit);
417 return d->selectionColor;
420 void QQuickTextEdit::setSelectionColor(const QColor &color)
423 if (d->selectionColor == color)
426 d->selectionColor = color;
427 QPalette pal = d->control->palette();
428 pal.setColor(QPalette::Highlight, color);
429 d->control->setPalette(pal);
431 emit selectionColorChanged(d->selectionColor);
435 \qmlproperty color QtQuick2::TextEdit::selectedTextColor
437 The selected text color, used in selections.
439 QColor QQuickTextEdit::selectedTextColor() const
441 Q_D(const QQuickTextEdit);
442 return d->selectedTextColor;
445 void QQuickTextEdit::setSelectedTextColor(const QColor &color)
448 if (d->selectedTextColor == color)
451 d->selectedTextColor = color;
452 QPalette pal = d->control->palette();
453 pal.setColor(QPalette::HighlightedText, color);
454 d->control->setPalette(pal);
456 emit selectedTextColorChanged(d->selectedTextColor);
460 \qmlproperty enumeration QtQuick2::TextEdit::horizontalAlignment
461 \qmlproperty enumeration QtQuick2::TextEdit::verticalAlignment
462 \qmlproperty enumeration QtQuick2::TextEdit::effectiveHorizontalAlignment
464 Sets the horizontal and vertical alignment of the text within the TextEdit item's
465 width and height. By default, the text alignment follows the natural alignment
466 of the text, for example text that is read from left to right will be aligned to
469 Valid values for \c horizontalAlignment are:
471 \o TextEdit.AlignLeft (default)
472 \o TextEdit.AlignRight
473 \o TextEdit.AlignHCenter
474 \o TextEdit.AlignJustify
477 Valid values for \c verticalAlignment are:
479 \o TextEdit.AlignTop (default)
480 \o TextEdit.AlignBottom
481 \o TextEdit.AlignVCenter
484 When using the attached property LayoutMirroring::enabled to mirror application
485 layouts, the horizontal alignment of text will also be mirrored. However, the property
486 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
487 of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
489 QQuickTextEdit::HAlignment QQuickTextEdit::hAlign() const
491 Q_D(const QQuickTextEdit);
495 void QQuickTextEdit::setHAlign(HAlignment align)
498 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
499 d->hAlignImplicit = false;
500 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
501 d->updateDefaultTextOption();
506 void QQuickTextEdit::resetHAlign()
509 d->hAlignImplicit = true;
510 if (d->determineHorizontalAlignment() && isComponentComplete()) {
511 d->updateDefaultTextOption();
516 QQuickTextEdit::HAlignment QQuickTextEdit::effectiveHAlign() const
518 Q_D(const QQuickTextEdit);
519 QQuickTextEdit::HAlignment effectiveAlignment = d->hAlign;
520 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
522 case QQuickTextEdit::AlignLeft:
523 effectiveAlignment = QQuickTextEdit::AlignRight;
525 case QQuickTextEdit::AlignRight:
526 effectiveAlignment = QQuickTextEdit::AlignLeft;
532 return effectiveAlignment;
535 bool QQuickTextEditPrivate::setHAlign(QQuickTextEdit::HAlignment alignment, bool forceAlign)
538 if (hAlign != alignment || forceAlign) {
539 QQuickTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
541 emit q->horizontalAlignmentChanged(alignment);
542 if (oldEffectiveHAlign != q->effectiveHAlign())
543 emit q->effectiveHorizontalAlignmentChanged();
549 bool QQuickTextEditPrivate::determineHorizontalAlignment()
552 if (hAlignImplicit && q->isComponentComplete()) {
554 if (document->isEmpty()) {
555 const QString preeditText = control->textCursor().block().layout()->preeditAreaText();
556 alignToRight = preeditText.isEmpty()
557 ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft
558 : preeditText.isRightToLeft();
560 alignToRight = rightToLeftText;
562 return setHAlign(alignToRight ? QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft);
567 void QQuickTextEditPrivate::mirrorChange()
570 if (q->isComponentComplete()) {
571 if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) {
572 updateDefaultTextOption();
574 emit q->effectiveHorizontalAlignmentChanged();
579 QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const
581 Q_D(const QQuickTextEdit);
585 void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment)
588 if (alignment == d->vAlign)
590 d->vAlign = alignment;
591 d->updateDefaultTextOption();
593 moveCursorDelegate();
594 emit verticalAlignmentChanged(d->vAlign);
597 \qmlproperty enumeration QtQuick2::TextEdit::wrapMode
599 Set this property to wrap the text to the TextEdit item's width.
600 The text will only wrap if an explicit width has been set.
603 \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
604 \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
605 \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
606 \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.
609 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
611 QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode() const
613 Q_D(const QQuickTextEdit);
617 void QQuickTextEdit::setWrapMode(WrapMode mode)
620 if (mode == d->wrapMode)
623 d->updateDefaultTextOption();
625 emit wrapModeChanged();
629 \qmlproperty int QtQuick2::TextEdit::lineCount
631 Returns the total number of lines in the textEdit item.
633 int QQuickTextEdit::lineCount() const
635 Q_D(const QQuickTextEdit);
640 \qmlproperty int QtQuick2::TextEdit::length
642 Returns the total number of plain text characters in the TextEdit item.
644 As this number doesn't include any formatting markup it may not be the same as the
645 length of the string returned by the \l text property.
647 This property can be faster than querying the length the \l text property as it doesn't
648 require any copying or conversion of the TextEdit's internal string data.
651 int QQuickTextEdit::length() const
653 Q_D(const QQuickTextEdit);
654 // QTextDocument::characterCount() includes the terminating null character.
655 return qMax(0, d->document->characterCount() - 1);
659 \qmlproperty real QtQuick2::TextEdit::contentWidth
661 Returns the width of the text, including the width past the width
662 which is covered due to insufficient wrapping if \l wrapMode is set.
664 qreal QQuickTextEdit::contentWidth() const
666 Q_D(const QQuickTextEdit);
667 return d->contentSize.width();
671 \qmlproperty real QtQuick2::TextEdit::contentHeight
673 Returns the height of the text, including the height past the height
674 that is covered if the text does not fit within the set height.
676 qreal QQuickTextEdit::contentHeight() const
678 Q_D(const QQuickTextEdit);
679 return d->contentSize.height();
683 \qmlproperty url QtQuick2::TextEdit::baseUrl
685 This property specifies a base URL which is used to resolve relative URLs
688 By default is the url of the TextEdit element.
691 QUrl QQuickTextEdit::baseUrl() const
693 Q_D(const QQuickTextEdit);
694 if (d->baseUrl.isEmpty()) {
695 if (QQmlContext *context = qmlContext(this))
696 const_cast<QQuickTextEditPrivate *>(d)->baseUrl = context->baseUrl();
701 void QQuickTextEdit::setBaseUrl(const QUrl &url)
704 if (baseUrl() != url) {
707 d->document->setBaseUrl(url, d->richText);
708 emit baseUrlChanged();
712 void QQuickTextEdit::resetBaseUrl()
714 if (QQmlContext *context = qmlContext(this))
715 setBaseUrl(context->baseUrl());
721 \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position)
723 Returns the rectangle at the given \a position in the text. The x, y,
724 and height properties correspond to the cursor that would describe
727 QRectF QQuickTextEdit::positionToRectangle(int pos) const
729 Q_D(const QQuickTextEdit);
730 QTextCursor c(d->document);
732 return d->control->cursorRect(c).translated(0, d->yoff);
737 \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y)
739 Returns the text position closest to pixel position (\a x, \a y).
741 Position 0 is before the first character, position 1 is after the first character
742 but before the second, and so on until position \l {text}.length, which is after all characters.
744 int QQuickTextEdit::positionAt(int x, int y) const
746 Q_D(const QQuickTextEdit);
747 int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
748 QTextCursor cursor = d->control->textCursor();
749 if (r > cursor.position()) {
750 // The cursor position includes positions within the preedit text, but only positions in the
751 // same text block are offset so it is possible to get a position that is either part of the
752 // preedit or the next text block.
753 QTextLayout *layout = cursor.block().layout();
754 const int preeditLength = layout
755 ? layout->preeditAreaText().length()
757 if (preeditLength > 0
758 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
759 r = r > cursor.position() + preeditLength
768 \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
770 Moves the cursor to \a position and updates the selection according to the optional \a mode
771 parameter. (To only move the cursor, set the \l cursorPosition property.)
773 When this method is called it additionally sets either the
774 selectionStart or the selectionEnd (whichever was at the previous cursor position)
775 to the specified position. This allows you to easily extend and contract the selected
778 The selection mode specifies whether the selection is updated on a per character or a per word
779 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
782 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
783 the previous cursor position) to the specified position.
784 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
785 words between the specified position and the previous cursor position. Words partially in the
789 For example, take this sequence of calls:
793 moveCursorSelection(9, TextEdit.SelectCharacters)
794 moveCursorSelection(7, TextEdit.SelectCharacters)
797 This moves the cursor to position 5, extend the selection end from 5 to 9
798 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
799 selected (the 6th and 7th characters).
801 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
802 before or on position 5 and extend the selection end to a word boundary on or past position 9.
804 void QQuickTextEdit::moveCursorSelection(int pos)
806 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
808 QTextCursor cursor = d->control->textCursor();
809 if (cursor.position() == pos)
811 cursor.setPosition(pos, QTextCursor::KeepAnchor);
812 d->control->setTextCursor(cursor);
815 void QQuickTextEdit::moveCursorSelection(int pos, SelectionMode mode)
818 QTextCursor cursor = d->control->textCursor();
819 if (cursor.position() == pos)
821 if (mode == SelectCharacters) {
822 cursor.setPosition(pos, QTextCursor::KeepAnchor);
823 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
824 if (cursor.anchor() > cursor.position()) {
825 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
826 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
827 if (cursor.position() == cursor.anchor())
828 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
830 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
832 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
833 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
836 cursor.setPosition(pos, QTextCursor::KeepAnchor);
837 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
838 if (cursor.position() != pos)
839 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
840 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
841 if (cursor.anchor() < cursor.position()) {
842 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
843 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
845 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
846 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
847 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
848 if (cursor.position() != cursor.anchor()) {
849 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
850 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
854 cursor.setPosition(pos, QTextCursor::KeepAnchor);
855 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
856 if (cursor.position() != pos) {
857 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
858 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
861 d->control->setTextCursor(cursor);
865 \qmlproperty bool QtQuick2::TextEdit::cursorVisible
866 If true the text edit shows a cursor.
868 This property is set and unset when the text edit gets active focus, but it can also
869 be set directly (useful, for example, if a KeyProxy might forward keys to it).
871 bool QQuickTextEdit::isCursorVisible() const
873 Q_D(const QQuickTextEdit);
874 return d->cursorVisible;
877 void QQuickTextEdit::setCursorVisible(bool on)
880 if (d->cursorVisible == on)
882 d->cursorVisible = on;
883 QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
884 if (!on && !d->persistentSelection)
885 d->control->setCursorIsFocusIndicator(true);
886 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
887 emit cursorVisibleChanged(d->cursorVisible);
891 \qmlproperty int QtQuick2::TextEdit::cursorPosition
892 The position of the cursor in the TextEdit.
894 int QQuickTextEdit::cursorPosition() const
896 Q_D(const QQuickTextEdit);
897 return d->control->textCursor().position();
900 void QQuickTextEdit::setCursorPosition(int pos)
903 if (pos < 0 || pos >= d->document->characterCount()) // characterCount includes the terminating null.
905 QTextCursor cursor = d->control->textCursor();
906 if (cursor.position() == pos && cursor.anchor() == pos)
908 cursor.setPosition(pos);
909 d->control->setTextCursor(cursor);
913 \qmlproperty Component QtQuick2::TextEdit::cursorDelegate
914 The delegate for the cursor in the TextEdit.
916 If you set a cursorDelegate for a TextEdit, this delegate will be used for
917 drawing the cursor instead of the standard cursor. An instance of the
918 delegate will be created and managed by the text edit when a cursor is
919 needed, and the x and y properties of delegate instance will be set so as
920 to be one pixel before the top left of the current character.
922 Note that the root item of the delegate component must be a QQuickItem or
923 QQuickItem derived item.
925 QQmlComponent* QQuickTextEdit::cursorDelegate() const
927 Q_D(const QQuickTextEdit);
928 return d->cursorComponent;
931 void QQuickTextEdit::setCursorDelegate(QQmlComponent* c)
934 if (d->cursorComponent) {
936 d->control->setCursorWidth(-1);
942 d->cursorComponent = c;
943 if (c && c->isReady()) {
944 loadCursorDelegate();
947 connect(c, SIGNAL(statusChanged()),
948 this, SLOT(loadCursorDelegate()));
951 emit cursorDelegateChanged();
954 void QQuickTextEdit::loadCursorDelegate()
957 if (d->cursorComponent->isLoading() || !isComponentComplete())
959 QQmlContext *creationContext = d->cursorComponent->creationContext();
960 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
961 d->cursor = qobject_cast<QQuickItem*>(object);
963 d->control->setCursorWidth(0);
965 QQml_setParent_noEvent(d->cursor, this);
966 d->cursor->setParentItem(this);
967 d->cursor->setHeight(QFontMetrics(d->font).height());
968 moveCursorDelegate();
971 qmlInfo(this) << "Error loading cursor delegate.";
976 \qmlproperty int QtQuick2::TextEdit::selectionStart
978 The cursor position before the first character in the current selection.
980 This property is read-only. To change the selection, use select(start,end),
981 selectAll(), or selectWord().
983 \sa selectionEnd, cursorPosition, selectedText
985 int QQuickTextEdit::selectionStart() const
987 Q_D(const QQuickTextEdit);
988 return d->control->textCursor().selectionStart();
992 \qmlproperty int QtQuick2::TextEdit::selectionEnd
994 The cursor position after the last character in the current selection.
996 This property is read-only. To change the selection, use select(start,end),
997 selectAll(), or selectWord().
999 \sa selectionStart, cursorPosition, selectedText
1001 int QQuickTextEdit::selectionEnd() const
1003 Q_D(const QQuickTextEdit);
1004 return d->control->textCursor().selectionEnd();
1008 \qmlproperty string QtQuick2::TextEdit::selectedText
1010 This read-only property provides the text currently selected in the
1013 It is equivalent to the following snippet, but is faster and easier
1016 //myTextEdit is the id of the TextEdit
1017 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
1018 myTextEdit.selectionEnd);
1021 QString QQuickTextEdit::selectedText() const
1023 Q_D(const QQuickTextEdit);
1024 return d->control->textCursor().selectedText();
1028 \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress
1030 Whether the TextEdit should gain active focus on a mouse press. By default this is
1033 bool QQuickTextEdit::focusOnPress() const
1035 Q_D(const QQuickTextEdit);
1036 return d->focusOnPress;
1039 void QQuickTextEdit::setFocusOnPress(bool on)
1041 Q_D(QQuickTextEdit);
1042 if (d->focusOnPress == on)
1044 d->focusOnPress = on;
1045 emit activeFocusOnPressChanged(d->focusOnPress);
1049 \qmlproperty bool QtQuick2::TextEdit::persistentSelection
1051 Whether the TextEdit should keep the selection visible when it loses active focus to another
1052 item in the scene. By default this is set to true;
1054 bool QQuickTextEdit::persistentSelection() const
1056 Q_D(const QQuickTextEdit);
1057 return d->persistentSelection;
1060 void QQuickTextEdit::setPersistentSelection(bool on)
1062 Q_D(QQuickTextEdit);
1063 if (d->persistentSelection == on)
1065 d->persistentSelection = on;
1066 emit persistentSelectionChanged(d->persistentSelection);
1070 \qmlproperty real QtQuick2::TextEdit::textMargin
1072 The margin, in pixels, around the text in the TextEdit.
1074 qreal QQuickTextEdit::textMargin() const
1076 Q_D(const QQuickTextEdit);
1077 return d->textMargin;
1080 void QQuickTextEdit::setTextMargin(qreal margin)
1082 Q_D(QQuickTextEdit);
1083 if (d->textMargin == margin)
1085 d->textMargin = margin;
1086 d->document->setDocumentMargin(d->textMargin);
1087 emit textMarginChanged(d->textMargin);
1091 \qmlproperty enumeration QtQuick2::TextEdit::inputMethodHints
1093 Provides hints to the input method about the expected content of the text edit and how it
1096 The value is a bit-wise combination of flags or Qt.ImhNone if no hints are set.
1098 Flags that alter behaviour are:
1101 \o Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1102 \o Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1103 in any persistent storage like predictive user dictionary.
1104 \o Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1105 when a sentence ends.
1106 \o Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1107 \o Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1108 \o Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1109 \o Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1111 \o Qt.ImhDate - The text editor functions as a date field.
1112 \o Qt.ImhTime - The text editor functions as a time field.
1115 Flags that restrict input (exclusive flags) are:
1118 \o Qt.ImhDigitsOnly - Only digits are allowed.
1119 \o Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1120 \o Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1121 \o Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1122 \o Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1123 \o Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1124 \o Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1130 \o Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1134 Qt::InputMethodHints QQuickTextEdit::inputMethodHints() const
1136 Q_D(const QQuickTextEdit);
1137 return d->inputMethodHints;
1140 void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints)
1142 Q_D(QQuickTextEdit);
1144 if (hints == d->inputMethodHints)
1147 d->inputMethodHints = hints;
1148 updateInputMethod(Qt::ImHints);
1149 emit inputMethodHintsChanged();
1152 void QQuickTextEdit::geometryChanged(const QRectF &newGeometry,
1153 const QRectF &oldGeometry)
1155 if (newGeometry.width() != oldGeometry.width())
1157 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1161 Ensures any delayed caching or data loading the class
1162 needs to performed is complete.
1164 void QQuickTextEdit::componentComplete()
1166 Q_D(QQuickTextEdit);
1167 QQuickImplicitSizeItem::componentComplete();
1169 d->document->setBaseUrl(baseUrl(), d->richText);
1171 d->determineHorizontalAlignment();
1172 d->updateDefaultTextOption();
1176 if (d->cursorComponent && d->cursorComponent->isReady())
1177 loadCursorDelegate();
1180 \qmlproperty bool QtQuick2::TextEdit::selectByMouse
1184 If true, the user can use the mouse to select text in some
1185 platform-specific way. Note that for some platforms this may
1186 not be an appropriate interaction (eg. may conflict with how
1187 the text needs to behave inside a Flickable.
1189 bool QQuickTextEdit::selectByMouse() const
1191 Q_D(const QQuickTextEdit);
1192 return d->selectByMouse;
1195 void QQuickTextEdit::setSelectByMouse(bool on)
1197 Q_D(QQuickTextEdit);
1198 if (d->selectByMouse != on) {
1199 d->selectByMouse = on;
1200 setKeepMouseGrab(on);
1202 setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1204 setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1205 emit selectByMouseChanged(on);
1210 \qmlproperty enum QtQuick2::TextEdit::mouseSelectionMode
1212 Specifies how text should be selected using a mouse.
1215 \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1216 \o TextEdit.SelectWords - The selection is updated with whole words.
1219 This property only applies when \l selectByMouse is true.
1221 QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode() const
1223 Q_D(const QQuickTextEdit);
1224 return d->mouseSelectionMode;
1227 void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode)
1229 Q_D(QQuickTextEdit);
1230 if (d->mouseSelectionMode != mode) {
1231 d->mouseSelectionMode = mode;
1232 d->control->setWordSelectionEnabled(mode == SelectWords);
1233 emit mouseSelectionModeChanged(mode);
1238 \qmlproperty bool QtQuick2::TextEdit::readOnly
1240 Whether the user can interact with the TextEdit item. If this
1241 property is set to true the text cannot be edited by user interaction.
1243 By default this property is false.
1245 void QQuickTextEdit::setReadOnly(bool r)
1247 Q_D(QQuickTextEdit);
1248 if (r == isReadOnly())
1251 setFlag(QQuickItem::ItemAcceptsInputMethod, !r);
1252 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1253 if (d->selectByMouse)
1254 flags = flags | Qt::TextSelectableByMouse;
1256 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1257 d->control->setTextInteractionFlags(flags);
1259 d->control->moveCursor(QTextCursor::End);
1261 updateInputMethod(Qt::ImEnabled);
1262 q_canPasteChanged();
1263 emit readOnlyChanged(r);
1266 bool QQuickTextEdit::isReadOnly() const
1268 Q_D(const QQuickTextEdit);
1269 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1273 Sets how the text edit should interact with user input to the given
1276 void QQuickTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1278 Q_D(QQuickTextEdit);
1279 d->control->setTextInteractionFlags(flags);
1283 Returns the flags specifying how the text edit should interact
1286 Qt::TextInteractionFlags QQuickTextEdit::textInteractionFlags() const
1288 Q_D(const QQuickTextEdit);
1289 return d->control->textInteractionFlags();
1293 \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle
1295 The rectangle where the standard text cursor is rendered
1296 within the text edit. Read-only.
1298 The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
1299 automatically when it changes. The width of the delegate is unaffected by changes in the
1302 QRect QQuickTextEdit::cursorRectangle() const
1304 Q_D(const QQuickTextEdit);
1305 return d->control->cursorRect().toRect().translated(0,d->yoff);
1308 bool QQuickTextEdit::event(QEvent *event)
1310 Q_D(QQuickTextEdit);
1311 if (event->type() == QEvent::ShortcutOverride) {
1312 d->control->processEvent(event, QPointF(0, -d->yoff));
1313 return event->isAccepted();
1315 return QQuickImplicitSizeItem::event(event);
1320 Handles the given key \a event.
1322 void QQuickTextEdit::keyPressEvent(QKeyEvent *event)
1324 Q_D(QQuickTextEdit);
1325 d->control->processEvent(event, QPointF(0, -d->yoff));
1326 if (!event->isAccepted())
1327 QQuickImplicitSizeItem::keyPressEvent(event);
1332 Handles the given key \a event.
1334 void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event)
1336 Q_D(QQuickTextEdit);
1337 d->control->processEvent(event, QPointF(0, -d->yoff));
1338 if (!event->isAccepted())
1339 QQuickImplicitSizeItem::keyReleaseEvent(event);
1343 \qmlmethod void QtQuick2::TextEdit::deselect()
1345 Removes active text selection.
1347 void QQuickTextEdit::deselect()
1349 Q_D(QQuickTextEdit);
1350 QTextCursor c = d->control->textCursor();
1352 d->control->setTextCursor(c);
1356 \qmlmethod void QtQuick2::TextEdit::selectAll()
1358 Causes all text to be selected.
1360 void QQuickTextEdit::selectAll()
1362 Q_D(QQuickTextEdit);
1363 d->control->selectAll();
1367 \qmlmethod void QtQuick2::TextEdit::selectWord()
1369 Causes the word closest to the current cursor position to be selected.
1371 void QQuickTextEdit::selectWord()
1373 Q_D(QQuickTextEdit);
1374 QTextCursor c = d->control->textCursor();
1375 c.select(QTextCursor::WordUnderCursor);
1376 d->control->setTextCursor(c);
1380 \qmlmethod void QtQuick2::TextEdit::select(int start, int end)
1382 Causes the text from \a start to \a end to be selected.
1384 If either start or end is out of range, the selection is not changed.
1386 After calling this, selectionStart will become the lesser
1387 and selectionEnd will become the greater (regardless of the order passed
1390 \sa selectionStart, selectionEnd
1392 void QQuickTextEdit::select(int start, int end)
1394 Q_D(QQuickTextEdit);
1395 if (start < 0 || end < 0 || start >= d->document->characterCount() || end >= d->document->characterCount())
1397 QTextCursor cursor = d->control->textCursor();
1398 cursor.beginEditBlock();
1399 cursor.setPosition(start, QTextCursor::MoveAnchor);
1400 cursor.setPosition(end, QTextCursor::KeepAnchor);
1401 cursor.endEditBlock();
1402 d->control->setTextCursor(cursor);
1405 updateSelectionMarkers();
1409 \qmlmethod void QtQuick2::TextEdit::isRightToLeft(int start, int end)
1411 Returns true if the natural reading direction of the editor text
1412 found between positions \a start and \a end is right to left.
1414 bool QQuickTextEdit::isRightToLeft(int start, int end)
1417 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1420 return getText(start, end).isRightToLeft();
1424 #ifndef QT_NO_CLIPBOARD
1426 \qmlmethod QtQuick2::TextEdit::cut()
1428 Moves the currently selected text to the system clipboard.
1430 void QQuickTextEdit::cut()
1432 Q_D(QQuickTextEdit);
1437 \qmlmethod QtQuick2::TextEdit::copy()
1439 Copies the currently selected text to the system clipboard.
1441 void QQuickTextEdit::copy()
1443 Q_D(QQuickTextEdit);
1448 \qmlmethod QtQuick2::TextEdit::paste()
1450 Replaces the currently selected text by the contents of the system clipboard.
1452 void QQuickTextEdit::paste()
1454 Q_D(QQuickTextEdit);
1455 d->control->paste();
1457 #endif // QT_NO_CLIPBOARD
1461 Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1462 current selection, and updates the selection start to the current cursor
1466 void QQuickTextEdit::undo()
1468 Q_D(QQuickTextEdit);
1473 Redoes the last operation if redo is \l {canRedo}{available}.
1476 void QQuickTextEdit::redo()
1478 Q_D(QQuickTextEdit);
1484 Handles the given mouse \a event.
1486 void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
1488 Q_D(QQuickTextEdit);
1489 if (d->focusOnPress){
1490 bool hadActiveFocus = hasActiveFocus();
1492 // re-open input panel on press if already focused
1493 if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
1494 openSoftwareInputPanel();
1496 d->control->processEvent(event, QPointF(0, -d->yoff));
1497 if (!event->isAccepted())
1498 QQuickImplicitSizeItem::mousePressEvent(event);
1503 Handles the given mouse \a event.
1505 void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
1507 Q_D(QQuickTextEdit);
1508 d->control->processEvent(event, QPointF(0, -d->yoff));
1510 if (!event->isAccepted())
1511 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1516 Handles the given mouse \a event.
1518 void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
1520 Q_D(QQuickTextEdit);
1521 d->control->processEvent(event, QPointF(0, -d->yoff));
1522 if (!event->isAccepted())
1523 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1528 Handles the given mouse \a event.
1530 void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
1532 Q_D(QQuickTextEdit);
1533 d->control->processEvent(event, QPointF(0, -d->yoff));
1534 if (!event->isAccepted())
1535 QQuickImplicitSizeItem::mouseMoveEvent(event);
1540 Handles the given input method \a event.
1542 void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
1544 Q_D(QQuickTextEdit);
1545 const bool wasComposing = isInputMethodComposing();
1546 d->control->processEvent(event, QPointF(0, -d->yoff));
1547 if (wasComposing != isInputMethodComposing())
1548 emit inputMethodComposingChanged();
1551 void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1553 if (change == ItemActiveFocusHasChanged) {
1554 setCursorVisible(value.boolValue); // ### refactor: focus handling && d->canvas && d->canvas->hasFocus());
1556 if (value.boolValue) {
1557 q_updateAlignment();
1558 connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1559 this, SLOT(q_updateAlignment()));
1561 disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1562 this, SLOT(q_updateAlignment()));
1565 QQuickItem::itemChange(change, value);
1570 Returns the value of the given \a property.
1572 QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1574 Q_D(const QQuickTextEdit);
1579 v = (bool)(flags() & ItemAcceptsInputMethod);
1582 v = (int)inputMethodHints();
1585 v = d->control->inputMethodQuery(property);
1592 void QQuickTextEdit::triggerPreprocess()
1594 Q_D(QQuickTextEdit);
1595 if (d->updateType == QQuickTextEditPrivate::UpdateNone)
1596 d->updateType = QQuickTextEditPrivate::UpdateOnlyPreprocess;
1600 QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1602 Q_UNUSED(updatePaintNodeData);
1603 Q_D(QQuickTextEdit);
1605 if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode && oldNode != 0) {
1606 // Update done in preprocess() in the nodes
1607 d->updateType = QQuickTextEditPrivate::UpdateNone;
1611 d->updateType = QQuickTextEditPrivate::UpdateNone;
1613 QSGNode *currentNode = oldNode;
1614 if (oldNode == 0 || d->documentDirty) {
1615 d->documentDirty = false;
1617 #if defined(Q_OS_MAC)
1618 // Make sure document is relayouted in the paint node on Mac
1619 // to avoid crashes due to the font engines created in the
1621 d->document->markContentsDirty(0, d->document->characterCount());
1624 QQuickTextNode *node = 0;
1626 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1629 node = static_cast<QQuickTextNode *>(oldNode);
1632 node->deleteContent();
1633 node->setMatrix(QMatrix4x4());
1635 QRectF bounds = boundingRect();
1637 QColor selectionColor = d->control->palette().color(QPalette::Highlight);
1638 QColor selectedTextColor = d->control->palette().color(QPalette::HighlightedText);
1639 node->addTextDocument(bounds.topLeft(), d->document, d->color, QQuickText::Normal, QColor(),
1640 selectionColor, selectedTextColor, selectionStart(),
1641 selectionEnd() - 1); // selectionEnd() returns first char after
1644 #if defined(Q_OS_MAC)
1645 // We also need to make sure the document layout is redone when
1646 // control is returned to the main thread, as all the font engines
1647 // are now owned by the rendering thread
1648 d->document->markContentsDirty(0, d->document->characterCount());
1652 if (d->cursorComponent == 0 && !isReadOnly()) {
1653 QQuickTextNode *node = static_cast<QQuickTextNode *>(currentNode);
1655 QColor color = (!d->cursorVisible || !d->control->cursorOn())
1656 ? QColor(0, 0, 0, 0)
1659 if (node->cursorNode() == 0) {
1660 node->setCursor(cursorRectangle(), color);
1662 node->cursorNode()->setRect(cursorRectangle());
1663 node->cursorNode()->setColor(color);
1672 \qmlproperty bool QtQuick2::TextEdit::smooth
1674 This property holds whether the text is smoothly scaled or transformed.
1676 Smooth filtering gives better visual quality, but is slower. If
1677 the item is displayed at its natural size, this property has no visual or
1680 \note Generally scaling artifacts are only visible if the item is stationary on
1681 the screen. A common pattern when animating an item is to disable smooth
1682 filtering at the beginning of the animation and reenable it at the conclusion.
1686 \qmlproperty bool QtQuick2::TextEdit::canPaste
1688 Returns true if the TextEdit is writable and the content of the clipboard is
1689 suitable for pasting into the TextEdit.
1691 bool QQuickTextEdit::canPaste() const
1693 Q_D(const QQuickTextEdit);
1694 if (!d->canPasteValid) {
1695 const_cast<QQuickTextEditPrivate *>(d)->canPaste = d->control->canPaste();
1696 const_cast<QQuickTextEditPrivate *>(d)->canPasteValid = true;
1702 \qmlproperty bool QtQuick2::TextEdit::canUndo
1704 Returns true if the TextEdit is writable and there are previous operations
1708 bool QQuickTextEdit::canUndo() const
1710 Q_D(const QQuickTextEdit);
1711 return d->document->isUndoAvailable();
1715 \qmlproperty bool QtQuick2::TextEdit::canRedo
1717 Returns true if the TextEdit is writable and there are \l {undo}{undone}
1718 operations that can be redone.
1721 bool QQuickTextEdit::canRedo() const
1723 Q_D(const QQuickTextEdit);
1724 return d->document->isRedoAvailable();
1728 \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1731 This property holds whether the TextEdit has partial text input from an
1734 While it is composing an input method may rely on mouse or key events from
1735 the TextEdit to edit or commit the partial text. This property can be used
1736 to determine when to disable events handlers that may interfere with the
1737 correct operation of an input method.
1739 bool QQuickTextEdit::isInputMethodComposing() const
1741 Q_D(const QQuickTextEdit);
1742 if (QTextLayout *layout = d->control->textCursor().block().layout())
1743 return layout->preeditAreaText().length() > 0;
1747 void QQuickTextEditPrivate::init()
1749 Q_Q(QQuickTextEdit);
1751 q->setSmooth(smooth);
1752 q->setAcceptedMouseButtons(Qt::LeftButton);
1753 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1754 q->setFlag(QQuickItem::ItemHasContents);
1756 document = new QQuickTextDocumentWithImageResources(q);
1758 control = new QQuickTextControl(document, q);
1759 control->setView(q);
1760 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1761 control->setAcceptRichText(false);
1762 control->setCursorIsFocusIndicator(true);
1764 // QQuickTextControl follows the default text color
1765 // defined by the platform, declarative text
1766 // should be black by default
1767 QPalette pal = control->palette();
1768 if (pal.color(QPalette::Text) != color) {
1769 pal.setColor(QPalette::Text, color);
1770 control->setPalette(pal);
1773 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateDocument()));
1774 QObject::connect(control, SIGNAL(updateCursorRequest()), q, SLOT(updateCursor()));
1775 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1776 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1777 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1778 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1779 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1780 QObject::connect(control, SIGNAL(cursorRectangleChanged()), q, SLOT(moveCursorDelegate()));
1781 QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1782 #ifndef QT_NO_CLIPBOARD
1783 QObject::connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1785 FAST_CONNECT(document, SIGNAL(undoAvailable(bool)), q, SIGNAL(canUndoChanged()));
1786 FAST_CONNECT(document, SIGNAL(redoAvailable(bool)), q, SIGNAL(canRedoChanged()));
1787 FAST_CONNECT(document, SIGNAL(imagesLoaded()), q, SLOT(updateSize()));
1789 document->setDefaultFont(font);
1790 document->setDocumentMargin(textMargin);
1791 document->setUndoRedoEnabled(false); // flush undo buffer.
1792 document->setUndoRedoEnabled(true);
1793 updateDefaultTextOption();
1796 void QQuickTextEdit::q_textChanged()
1798 Q_D(QQuickTextEdit);
1799 d->textCached = false;
1800 d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
1801 d->determineHorizontalAlignment();
1802 d->updateDefaultTextOption();
1808 void QQuickTextEdit::moveCursorDelegate()
1810 Q_D(QQuickTextEdit);
1811 d->determineHorizontalAlignment();
1812 updateInputMethod();
1813 emit cursorRectangleChanged();
1816 QRectF cursorRect = cursorRectangle();
1817 d->cursor->setX(cursorRect.x());
1818 d->cursor->setY(cursorRect.y());
1821 void QQuickTextEdit::updateSelectionMarkers()
1823 Q_D(QQuickTextEdit);
1824 if (d->lastSelectionStart != d->control->textCursor().selectionStart()) {
1825 d->lastSelectionStart = d->control->textCursor().selectionStart();
1826 emit selectionStartChanged();
1828 if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) {
1829 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1830 emit selectionEndChanged();
1834 QRectF QQuickTextEdit::boundingRect() const
1836 Q_D(const QQuickTextEdit);
1837 QRectF r = QQuickImplicitSizeItem::boundingRect();
1838 int cursorWidth = 1;
1840 cursorWidth = d->cursor->width();
1841 if (!d->document->isEmpty())
1842 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1844 // Could include font max left/right bearings to either side of rectangle.
1846 r.setRight(r.right() + cursorWidth);
1847 return r.translated(0,d->yoff);
1850 qreal QQuickTextEditPrivate::getImplicitWidth() const
1852 Q_Q(const QQuickTextEdit);
1853 if (!requireImplicitWidth) {
1854 // We don't calculate implicitWidth unless it is required.
1855 // We need to force a size update now to ensure implicitWidth is calculated
1856 const_cast<QQuickTextEditPrivate*>(this)->requireImplicitWidth = true;
1857 const_cast<QQuickTextEdit*>(q)->updateSize();
1859 return implicitWidth;
1862 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1863 // need to do all the calculations each time
1864 void QQuickTextEdit::updateSize()
1866 Q_D(QQuickTextEdit);
1867 if (isComponentComplete()) {
1868 qreal naturalWidth = d->implicitWidth;
1869 // ### assumes that if the width is set, the text will fill to edges
1870 // ### (unless wrap is false, then clipping will occur)
1872 if (!d->requireImplicitWidth) {
1873 emit implicitWidthChanged();
1874 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1875 if (d->requireImplicitWidth)
1878 if (d->requireImplicitWidth) {
1879 d->document->setTextWidth(-1);
1880 naturalWidth = d->document->idealWidth();
1882 if (d->document->textWidth() != width())
1883 d->document->setTextWidth(width());
1885 d->document->setTextWidth(-1);
1887 QFontMetrics fm = QFontMetrics(d->font);
1889 dy -= (int)d->document->size().height();
1892 if (heightValid()) {
1893 if (d->vAlign == AlignBottom)
1895 else if (d->vAlign == AlignVCenter)
1902 if (nyoff != d->yoff)
1904 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1906 //### need to comfirm cost of always setting these
1907 int newWidth = qCeil(d->document->idealWidth());
1908 if (!widthValid() && d->document->textWidth() != newWidth)
1909 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1910 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1914 else if (d->requireImplicitWidth)
1915 iWidth = naturalWidth;
1916 qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
1918 setImplicitSize(iWidth, newHeight);
1920 setImplicitHeight(newHeight);
1922 QSize size(newWidth, newHeight);
1923 if (d->contentSize != size) {
1924 d->contentSize = size;
1925 emit contentSizeChanged();
1933 void QQuickTextEdit::updateDocument()
1935 Q_D(QQuickTextEdit);
1936 d->documentDirty = true;
1938 if (isComponentComplete()) {
1939 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1944 void QQuickTextEdit::updateCursor()
1946 Q_D(QQuickTextEdit);
1947 if (isComponentComplete()) {
1948 d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1953 void QQuickTextEdit::q_updateAlignment()
1955 Q_D(QQuickTextEdit);
1956 if (d->determineHorizontalAlignment()) {
1957 d->updateDefaultTextOption();
1958 moveCursorDelegate();
1962 void QQuickTextEdit::updateTotalLines()
1964 Q_D(QQuickTextEdit);
1968 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1969 QTextLayout *layout = it.layout();
1972 subLines += layout->lineCount()-1;
1975 int newTotalLines = d->document->lineCount() + subLines;
1976 if (d->lineCount != newTotalLines) {
1977 d->lineCount = newTotalLines;
1978 emit lineCountChanged();
1982 void QQuickTextEditPrivate::updateDefaultTextOption()
1984 Q_Q(QQuickTextEdit);
1985 QTextOption opt = document->defaultTextOption();
1986 int oldAlignment = opt.alignment();
1988 QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
1989 if (rightToLeftText) {
1990 if (horizontalAlignment == QQuickTextEdit::AlignLeft)
1991 horizontalAlignment = QQuickTextEdit::AlignRight;
1992 else if (horizontalAlignment == QQuickTextEdit::AlignRight)
1993 horizontalAlignment = QQuickTextEdit::AlignLeft;
1995 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
1997 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1998 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
1999 opt.setUseDesignMetrics(true);
2001 if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
2004 document->setDefaultTextOption(opt);
2010 \qmlmethod void QtQuick2::TextEdit::openSoftwareInputPanel()
2012 Opens software input panels like virtual keyboards for typing, useful for
2013 customizing when you want the input keyboard to be shown and hidden in
2016 By default the opening of input panels follows the platform style. Input panels are
2017 always closed if no editor has active focus.
2019 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2020 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2021 the behavior you want.
2023 Only relevant on platforms, which provide virtual keyboards.
2029 text: "Hello world!"
2030 activeFocusOnPress: false
2032 anchors.fill: parent
2034 if (!textEdit.activeFocus) {
2035 textEdit.forceActiveFocus();
2036 textEdit.openSoftwareInputPanel();
2038 textEdit.focus = false;
2041 onPressAndHold: textEdit.closeSoftwareInputPanel();
2046 void QQuickTextEdit::openSoftwareInputPanel()
2049 qGuiApp->inputMethod()->show();
2053 \qmlmethod void QtQuick2::TextEdit::closeSoftwareInputPanel()
2055 Closes a software input panel like a virtual keyboard shown on the screen, useful
2056 for customizing when you want the input keyboard to be shown and hidden in
2059 By default the opening of input panels follows the platform style. Input panels are
2060 always closed if no editor has active focus.
2062 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2063 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2064 the behavior you want.
2066 Only relevant on platforms, which provide virtual keyboards.
2072 text: "Hello world!"
2073 activeFocusOnPress: false
2075 anchors.fill: parent
2077 if (!textEdit.activeFocus) {
2078 textEdit.forceActiveFocus();
2079 textEdit.openSoftwareInputPanel();
2081 textEdit.focus = false;
2084 onPressAndHold: textEdit.closeSoftwareInputPanel();
2089 void QQuickTextEdit::closeSoftwareInputPanel()
2092 qGuiApp->inputMethod()->hide();
2095 void QQuickTextEdit::focusInEvent(QFocusEvent *event)
2097 Q_D(const QQuickTextEdit);
2098 if (d->focusOnPress && !isReadOnly())
2099 openSoftwareInputPanel();
2100 QQuickImplicitSizeItem::focusInEvent(event);
2103 void QQuickTextEdit::q_canPasteChanged()
2105 Q_D(QQuickTextEdit);
2106 bool old = d->canPaste;
2107 d->canPaste = d->control->canPaste();
2108 bool changed = old!=d->canPaste || !d->canPasteValid;
2109 d->canPasteValid = true;
2111 emit canPasteChanged();
2115 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2117 Returns the section of text that is between the \a start and \a end positions.
2119 The returned text does not include any rich text formatting.
2122 QString QQuickTextEdit::getText(int start, int end) const
2124 Q_D(const QQuickTextEdit);
2125 start = qBound(0, start, d->document->characterCount() - 1);
2126 end = qBound(0, end, d->document->characterCount() - 1);
2127 QTextCursor cursor(d->document);
2128 cursor.setPosition(start, QTextCursor::MoveAnchor);
2129 cursor.setPosition(end, QTextCursor::KeepAnchor);
2130 return cursor.selectedText();
2134 \qmlmethod string QtQuick2::TextEdit::getFormattedText(int start, int end)
2136 Returns the section of text that is between the \a start and \a end positions.
2138 The returned text will be formatted according the \l textFormat property.
2141 QString QQuickTextEdit::getFormattedText(int start, int end) const
2143 Q_D(const QQuickTextEdit);
2145 start = qBound(0, start, d->document->characterCount() - 1);
2146 end = qBound(0, end, d->document->characterCount() - 1);
2148 QTextCursor cursor(d->document);
2149 cursor.setPosition(start, QTextCursor::MoveAnchor);
2150 cursor.setPosition(end, QTextCursor::KeepAnchor);
2153 #ifndef QT_NO_TEXTHTMLPARSER
2154 return cursor.selection().toHtml();
2156 return cursor.selection().toPlainText();
2159 return cursor.selection().toPlainText();
2164 \qmlmethod void QtQuick2::TextEdit::insert(int position, string text)
2166 Inserts \a text into the TextEdit at position.
2168 void QQuickTextEdit::insert(int position, const QString &text)
2170 Q_D(QQuickTextEdit);
2171 if (position < 0 || position >= d->document->characterCount())
2173 QTextCursor cursor(d->document);
2174 cursor.setPosition(position);
2175 d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text));
2177 #ifndef QT_NO_TEXTHTMLPARSER
2178 cursor.insertHtml(text);
2180 cursor.insertText(text);
2183 cursor.insertText(text);
2188 \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2190 Removes the section of text that is between the \a start and \a end positions from the TextEdit.
2193 void QQuickTextEdit::remove(int start, int end)
2195 Q_D(QQuickTextEdit);
2196 start = qBound(0, start, d->document->characterCount() - 1);
2197 end = qBound(0, end, d->document->characterCount() - 1);
2198 QTextCursor cursor(d->document);
2199 cursor.setPosition(start, QTextCursor::MoveAnchor);
2200 cursor.setPosition(end, QTextCursor::KeepAnchor);
2201 cursor.removeSelectedText();