1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qsgtextedit_p.h"
43 #include "qsgtextedit_p_p.h"
44 #include "qsgevents_p_p.h"
45 #include "qsgcanvas.h"
46 #include "qsgtextnode_p.h"
47 #include "qsgsimplerectnode.h"
49 #include <QtDeclarative/qdeclarativeinfo.h>
50 #include <QtGui/qapplication.h>
51 #include <QtGui/qgraphicssceneevent.h>
52 #include <QtGui/qpainter.h>
53 #include <QtGui/qtextobject.h>
54 #include <QtCore/qmath.h>
56 #include <private/qdeclarativeglobal_p.h>
57 #include <private/qtextcontrol_p.h>
58 #include <private/qtextengine_p.h>
59 #include <private/qwidget_p.h>
60 #include <private/qsgdistancefieldglyphcache_p.h>
61 #include <private/qsgtexture_p.h>
62 #include <private/qsgadaptationlayer_p.h>
66 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
68 QWidgetPrivate *qt_widget_private(QWidget *widget);
70 \qmlclass TextEdit QSGTextEdit
71 \inqmlmodule QtQuick 2
72 \ingroup qml-basic-visual-elements
73 \brief The TextEdit item displays multiple lines of editable formatted text.
76 The TextEdit item displays a block of editable, formatted text.
78 It can display both plain and rich text. For example:
83 text: "<b>Hello</b> <i>World!</i>"
84 font.family: "Helvetica"
91 \image declarative-textedit.gif
93 Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
95 Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
96 to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
98 \snippet snippets/declarative/texteditor.qml 0
100 A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible
101 scrollbar, or a scrollbar that fades in to show location, etc.
103 Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
104 be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
105 from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
107 You can translate between cursor positions (characters from the start of the document) and pixel
108 points using positionAt() and positionToRectangle().
110 \sa Text, TextInput, {declarative/text/textselection}{Text Selection example}
114 \qmlsignal QtQuick2::TextEdit::onLinkActivated(string link)
116 This handler is called when the user clicks on a link embedded in the text.
117 The link must be in rich text or HTML format and the
118 \a link string provides access to the particular link.
120 QSGTextEdit::QSGTextEdit(QSGItem *parent)
121 : QSGImplicitSizeItem(*(new QSGTextEditPrivate), parent)
127 QString QSGTextEdit::text() const
129 Q_D(const QSGTextEdit);
131 #ifndef QT_NO_TEXTHTMLPARSER
133 return d->document->toHtml();
136 return d->document->toPlainText();
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 QSGTextEdit::setText(const QString &text)
255 if (QSGTextEdit::text() == text)
258 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
260 #ifndef QT_NO_TEXTHTMLPARSER
261 d->control->setHtml(text);
263 d->control->setPlainText(text);
265 d->isComplexRichText = QSGTextNode::isComplexRichText(d->document);
267 d->control->setPlainText(text);
273 \qmlproperty enumeration QtQuick2::TextEdit::textFormat
275 The way the text property should be displayed.
279 \o TextEdit.PlainText
283 The default is TextEdit.AutoText. If the text format is TextEdit.AutoText the text edit
284 will automatically determine whether the text should be treated as
285 rich text. This determination is made using Qt::mightBeRichText().
294 text: "<b>Hello</b> <i>World!</i>"
298 textFormat: TextEdit.RichText
299 text: "<b>Hello</b> <i>World!</i>"
303 textFormat: TextEdit.PlainText
304 text: "<b>Hello</b> <i>World!</i>"
308 \o \image declarative-textformat.png
311 QSGTextEdit::TextFormat QSGTextEdit::textFormat() const
313 Q_D(const QSGTextEdit);
317 void QSGTextEdit::setTextFormat(TextFormat format)
320 if (format == d->format)
322 bool wasRich = d->richText;
323 d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
325 if (wasRich && !d->richText) {
326 d->control->setPlainText(d->text);
328 } else if (!wasRich && d->richText) {
329 #ifndef QT_NO_TEXTHTMLPARSER
330 d->control->setHtml(d->text);
332 d->control->setPlainText(d->text);
335 d->isComplexRichText = QSGTextNode::isComplexRichText(d->document);
338 d->control->setAcceptRichText(d->format != PlainText);
339 emit textFormatChanged(d->format);
342 QFont QSGTextEdit::font() const
344 Q_D(const QSGTextEdit);
345 return d->sourceFont;
348 void QSGTextEdit::setFont(const QFont &font)
351 if (d->sourceFont == font)
354 d->sourceFont = font;
355 QFont oldFont = d->font;
357 if (d->font.pointSizeF() != -1) {
359 qreal size = qRound(d->font.pointSizeF()*2.0);
360 d->font.setPointSizeF(size/2.0);
363 if (oldFont != d->font) {
364 d->document->setDefaultFont(d->font);
366 d->cursor->setHeight(QFontMetrics(d->font).height());
367 moveCursorDelegate();
372 emit fontChanged(d->sourceFont);
376 \qmlproperty color QtQuick2::TextEdit::color
381 // green text using hexadecimal notation
382 TextEdit { color: "#00FF00" }
386 // steelblue text using SVG color name
387 TextEdit { color: "steelblue" }
390 QColor QSGTextEdit::color() const
392 Q_D(const QSGTextEdit);
396 void QSGTextEdit::setColor(const QColor &color)
399 if (d->color == color)
403 QPalette pal = d->control->palette();
404 pal.setColor(QPalette::Text, color);
405 d->control->setPalette(pal);
407 emit colorChanged(d->color);
411 \qmlproperty color QtQuick2::TextEdit::selectionColor
413 The text highlight color, used behind selections.
415 QColor QSGTextEdit::selectionColor() const
417 Q_D(const QSGTextEdit);
418 return d->selectionColor;
421 void QSGTextEdit::setSelectionColor(const QColor &color)
424 if (d->selectionColor == color)
427 d->selectionColor = color;
428 QPalette pal = d->control->palette();
429 pal.setColor(QPalette::Highlight, color);
430 d->control->setPalette(pal);
432 emit selectionColorChanged(d->selectionColor);
436 \qmlproperty color QtQuick2::TextEdit::selectedTextColor
438 The selected text color, used in selections.
440 QColor QSGTextEdit::selectedTextColor() const
442 Q_D(const QSGTextEdit);
443 return d->selectedTextColor;
446 void QSGTextEdit::setSelectedTextColor(const QColor &color)
449 if (d->selectedTextColor == color)
452 d->selectedTextColor = color;
453 QPalette pal = d->control->palette();
454 pal.setColor(QPalette::HighlightedText, color);
455 d->control->setPalette(pal);
457 emit selectedTextColorChanged(d->selectedTextColor);
461 \qmlproperty enumeration QtQuick2::TextEdit::horizontalAlignment
462 \qmlproperty enumeration QtQuick2::TextEdit::verticalAlignment
463 \qmlproperty enumeration QtQuick2::TextEdit::effectiveHorizontalAlignment
465 Sets the horizontal and vertical alignment of the text within the TextEdit item's
466 width and height. By default, the text alignment follows the natural alignment
467 of the text, for example text that is read from left to right will be aligned to
470 Valid values for \c horizontalAlignment are:
472 \o TextEdit.AlignLeft (default)
473 \o TextEdit.AlignRight
474 \o TextEdit.AlignHCenter
475 \o TextEdit.AlignJustify
478 Valid values for \c verticalAlignment are:
480 \o TextEdit.AlignTop (default)
481 \o TextEdit.AlignBottom
482 \o TextEdit.AlignVCenter
485 When using the attached property LayoutMirroring::enabled to mirror application
486 layouts, the horizontal alignment of text will also be mirrored. However, the property
487 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
488 of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
490 QSGTextEdit::HAlignment QSGTextEdit::hAlign() const
492 Q_D(const QSGTextEdit);
496 void QSGTextEdit::setHAlign(HAlignment align)
499 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
500 d->hAlignImplicit = false;
501 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
502 d->updateDefaultTextOption();
507 void QSGTextEdit::resetHAlign()
510 d->hAlignImplicit = true;
511 if (d->determineHorizontalAlignment() && isComponentComplete()) {
512 d->updateDefaultTextOption();
517 QSGTextEdit::HAlignment QSGTextEdit::effectiveHAlign() const
519 Q_D(const QSGTextEdit);
520 QSGTextEdit::HAlignment effectiveAlignment = d->hAlign;
521 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
523 case QSGTextEdit::AlignLeft:
524 effectiveAlignment = QSGTextEdit::AlignRight;
526 case QSGTextEdit::AlignRight:
527 effectiveAlignment = QSGTextEdit::AlignLeft;
533 return effectiveAlignment;
536 bool QSGTextEditPrivate::setHAlign(QSGTextEdit::HAlignment alignment, bool forceAlign)
539 if (hAlign != alignment || forceAlign) {
540 QSGTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
542 emit q->horizontalAlignmentChanged(alignment);
543 if (oldEffectiveHAlign != q->effectiveHAlign())
544 emit q->effectiveHorizontalAlignmentChanged();
550 bool QSGTextEditPrivate::determineHorizontalAlignment()
553 if (hAlignImplicit && q->isComponentComplete()) {
554 bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
555 return setHAlign(alignToRight ? QSGTextEdit::AlignRight : QSGTextEdit::AlignLeft);
560 void QSGTextEditPrivate::mirrorChange()
563 if (q->isComponentComplete()) {
564 if (!hAlignImplicit && (hAlign == QSGTextEdit::AlignRight || hAlign == QSGTextEdit::AlignLeft)) {
565 updateDefaultTextOption();
567 emit q->effectiveHorizontalAlignmentChanged();
572 QSGTextEdit::VAlignment QSGTextEdit::vAlign() const
574 Q_D(const QSGTextEdit);
578 void QSGTextEdit::setVAlign(QSGTextEdit::VAlignment alignment)
581 if (alignment == d->vAlign)
583 d->vAlign = alignment;
584 d->updateDefaultTextOption();
586 moveCursorDelegate();
587 emit verticalAlignmentChanged(d->vAlign);
590 \qmlproperty enumeration QtQuick2::TextEdit::wrapMode
592 Set this property to wrap the text to the TextEdit item's width.
593 The text will only wrap if an explicit width has been set.
596 \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
597 \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
598 \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
599 \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.
602 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
604 QSGTextEdit::WrapMode QSGTextEdit::wrapMode() const
606 Q_D(const QSGTextEdit);
610 void QSGTextEdit::setWrapMode(WrapMode mode)
613 if (mode == d->wrapMode)
616 d->updateDefaultTextOption();
618 emit wrapModeChanged();
622 \qmlproperty int QtQuick2::TextEdit::lineCount
624 Returns the total number of lines in the textEdit item.
626 int QSGTextEdit::lineCount() const
628 Q_D(const QSGTextEdit);
633 \qmlproperty real QtQuick2::TextEdit::paintedWidth
635 Returns the width of the text, including the width past the width
636 which is covered due to insufficient wrapping if \l wrapMode is set.
638 qreal QSGTextEdit::paintedWidth() const
640 Q_D(const QSGTextEdit);
641 return d->paintedSize.width();
645 \qmlproperty real QtQuick2::TextEdit::paintedHeight
647 Returns the height of the text, including the height past the height
648 that is covered if the text does not fit within the set height.
650 qreal QSGTextEdit::paintedHeight() const
652 Q_D(const QSGTextEdit);
653 return d->paintedSize.height();
657 \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position)
659 Returns the rectangle at the given \a position in the text. The x, y,
660 and height properties correspond to the cursor that would describe
663 QRectF QSGTextEdit::positionToRectangle(int pos) const
665 Q_D(const QSGTextEdit);
666 QTextCursor c(d->document);
668 return d->control->cursorRect(c);
673 \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y)
675 Returns the text position closest to pixel position (\a x, \a y).
677 Position 0 is before the first character, position 1 is after the first character
678 but before the second, and so on until position \l {text}.length, which is after all characters.
680 int QSGTextEdit::positionAt(int x, int y) const
682 Q_D(const QSGTextEdit);
683 int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
684 QTextCursor cursor = d->control->textCursor();
685 if (r > cursor.position()) {
686 // The cursor position includes positions within the preedit text, but only positions in the
687 // same text block are offset so it is possible to get a position that is either part of the
688 // preedit or the next text block.
689 QTextLayout *layout = cursor.block().layout();
690 const int preeditLength = layout
691 ? layout->preeditAreaText().length()
693 if (preeditLength > 0
694 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
695 r = r > cursor.position() + preeditLength
704 \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
706 Moves the cursor to \a position and updates the selection according to the optional \a mode
707 parameter. (To only move the cursor, set the \l cursorPosition property.)
709 When this method is called it additionally sets either the
710 selectionStart or the selectionEnd (whichever was at the previous cursor position)
711 to the specified position. This allows you to easily extend and contract the selected
714 The selection mode specifies whether the selection is updated on a per character or a per word
715 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
718 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
719 the previous cursor position) to the specified position.
720 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
721 words between the specified postion and the previous cursor position. Words partially in the
725 For example, take this sequence of calls:
729 moveCursorSelection(9, TextEdit.SelectCharacters)
730 moveCursorSelection(7, TextEdit.SelectCharacters)
733 This moves the cursor to position 5, extend the selection end from 5 to 9
734 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
735 selected (the 6th and 7th characters).
737 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
738 before or on position 5 and extend the selection end to a word boundary on or past position 9.
740 void QSGTextEdit::moveCursorSelection(int pos)
742 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
744 QTextCursor cursor = d->control->textCursor();
745 if (cursor.position() == pos)
747 cursor.setPosition(pos, QTextCursor::KeepAnchor);
748 d->control->setTextCursor(cursor);
751 void QSGTextEdit::moveCursorSelection(int pos, SelectionMode mode)
754 QTextCursor cursor = d->control->textCursor();
755 if (cursor.position() == pos)
757 if (mode == SelectCharacters) {
758 cursor.setPosition(pos, QTextCursor::KeepAnchor);
759 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
760 if (cursor.anchor() > cursor.position()) {
761 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
762 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
763 if (cursor.position() == cursor.anchor())
764 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
766 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
768 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
769 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
772 cursor.setPosition(pos, QTextCursor::KeepAnchor);
773 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
774 if (cursor.position() != pos)
775 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
776 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
777 if (cursor.anchor() < cursor.position()) {
778 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
779 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
781 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
782 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
783 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
784 if (cursor.position() != cursor.anchor()) {
785 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
786 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
790 cursor.setPosition(pos, QTextCursor::KeepAnchor);
791 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
792 if (cursor.position() != pos) {
793 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
794 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
797 d->control->setTextCursor(cursor);
801 \qmlproperty bool QtQuick2::TextEdit::cursorVisible
802 If true the text edit shows a cursor.
804 This property is set and unset when the text edit gets active focus, but it can also
805 be set directly (useful, for example, if a KeyProxy might forward keys to it).
807 bool QSGTextEdit::isCursorVisible() const
809 Q_D(const QSGTextEdit);
810 return d->cursorVisible;
813 void QSGTextEdit::setCursorVisible(bool on)
816 if (d->cursorVisible == on)
818 d->cursorVisible = on;
819 QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
820 if (!on && !d->persistentSelection)
821 d->control->setCursorIsFocusIndicator(true);
822 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
823 emit cursorVisibleChanged(d->cursorVisible);
827 \qmlproperty int QtQuick2::TextEdit::cursorPosition
828 The position of the cursor in the TextEdit.
830 int QSGTextEdit::cursorPosition() const
832 Q_D(const QSGTextEdit);
833 return d->control->textCursor().position();
836 void QSGTextEdit::setCursorPosition(int pos)
839 if (pos < 0 || pos > d->text.length())
841 QTextCursor cursor = d->control->textCursor();
842 if (cursor.position() == pos && cursor.anchor() == pos)
844 cursor.setPosition(pos);
845 d->control->setTextCursor(cursor);
849 \qmlproperty Component QtQuick2::TextEdit::cursorDelegate
850 The delegate for the cursor in the TextEdit.
852 If you set a cursorDelegate for a TextEdit, this delegate will be used for
853 drawing the cursor instead of the standard cursor. An instance of the
854 delegate will be created and managed by the text edit when a cursor is
855 needed, and the x and y properties of delegate instance will be set so as
856 to be one pixel before the top left of the current character.
858 Note that the root item of the delegate component must be a QDeclarativeItem or
859 QDeclarativeItem derived item.
861 QDeclarativeComponent* QSGTextEdit::cursorDelegate() const
863 Q_D(const QSGTextEdit);
864 return d->cursorComponent;
867 void QSGTextEdit::setCursorDelegate(QDeclarativeComponent* c)
870 if(d->cursorComponent){
872 d->control->setCursorWidth(-1);
878 d->cursorComponent = c;
879 if(c && c->isReady()){
880 loadCursorDelegate();
883 connect(c, SIGNAL(statusChanged()),
884 this, SLOT(loadCursorDelegate()));
887 emit cursorDelegateChanged();
890 void QSGTextEdit::loadCursorDelegate()
893 if(d->cursorComponent->isLoading())
895 d->cursor = qobject_cast<QSGItem*>(d->cursorComponent->create(qmlContext(this)));
897 d->control->setCursorWidth(0);
899 QDeclarative_setParent_noEvent(d->cursor, this);
900 d->cursor->setParentItem(this);
901 d->cursor->setHeight(QFontMetrics(d->font).height());
902 moveCursorDelegate();
904 qmlInfo(this) << "Error loading cursor delegate.";
909 \qmlproperty int QtQuick2::TextEdit::selectionStart
911 The cursor position before the first character in the current selection.
913 This property is read-only. To change the selection, use select(start,end),
914 selectAll(), or selectWord().
916 \sa selectionEnd, cursorPosition, selectedText
918 int QSGTextEdit::selectionStart() const
920 Q_D(const QSGTextEdit);
921 return d->control->textCursor().selectionStart();
925 \qmlproperty int QtQuick2::TextEdit::selectionEnd
927 The cursor position after the last character in the current selection.
929 This property is read-only. To change the selection, use select(start,end),
930 selectAll(), or selectWord().
932 \sa selectionStart, cursorPosition, selectedText
934 int QSGTextEdit::selectionEnd() const
936 Q_D(const QSGTextEdit);
937 return d->control->textCursor().selectionEnd();
941 \qmlproperty string QtQuick2::TextEdit::selectedText
943 This read-only property provides the text currently selected in the
946 It is equivalent to the following snippet, but is faster and easier
949 //myTextEdit is the id of the TextEdit
950 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
951 myTextEdit.selectionEnd);
954 QString QSGTextEdit::selectedText() const
956 Q_D(const QSGTextEdit);
957 return d->control->textCursor().selectedText();
961 \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress
963 Whether the TextEdit should gain active focus on a mouse press. By default this is
966 bool QSGTextEdit::focusOnPress() const
968 Q_D(const QSGTextEdit);
969 return d->focusOnPress;
972 void QSGTextEdit::setFocusOnPress(bool on)
975 if (d->focusOnPress == on)
977 d->focusOnPress = on;
978 emit activeFocusOnPressChanged(d->focusOnPress);
982 \qmlproperty bool QtQuick2::TextEdit::persistentSelection
984 Whether the TextEdit should keep the selection visible when it loses active focus to another
985 item in the scene. By default this is set to true;
987 bool QSGTextEdit::persistentSelection() const
989 Q_D(const QSGTextEdit);
990 return d->persistentSelection;
993 void QSGTextEdit::setPersistentSelection(bool on)
996 if (d->persistentSelection == on)
998 d->persistentSelection = on;
999 emit persistentSelectionChanged(d->persistentSelection);
1003 \qmlproperty real QtQuick2::TextEdit::textMargin
1005 The margin, in pixels, around the text in the TextEdit.
1007 qreal QSGTextEdit::textMargin() const
1009 Q_D(const QSGTextEdit);
1010 return d->textMargin;
1013 void QSGTextEdit::setTextMargin(qreal margin)
1016 if (d->textMargin == margin)
1018 d->textMargin = margin;
1019 d->document->setDocumentMargin(d->textMargin);
1020 emit textMarginChanged(d->textMargin);
1023 void QSGTextEdit::geometryChanged(const QRectF &newGeometry,
1024 const QRectF &oldGeometry)
1026 if (newGeometry.width() != oldGeometry.width())
1028 QSGImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1032 Ensures any delayed caching or data loading the class
1033 needs to performed is complete.
1035 void QSGTextEdit::componentComplete()
1038 QSGImplicitSizeItem::componentComplete();
1041 d->isComplexRichText = QSGTextNode::isComplexRichText(d->document);
1045 d->determineHorizontalAlignment();
1046 d->updateDefaultTextOption();
1053 \qmlproperty bool QtQuick2::TextEdit::selectByMouse
1057 If true, the user can use the mouse to select text in some
1058 platform-specific way. Note that for some platforms this may
1059 not be an appropriate interaction (eg. may conflict with how
1060 the text needs to behave inside a Flickable.
1062 bool QSGTextEdit::selectByMouse() const
1064 Q_D(const QSGTextEdit);
1065 return d->selectByMouse;
1068 void QSGTextEdit::setSelectByMouse(bool on)
1071 if (d->selectByMouse != on) {
1072 d->selectByMouse = on;
1073 setKeepMouseGrab(on);
1075 setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1077 setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1078 emit selectByMouseChanged(on);
1083 \qmlproperty enum QtQuick2::TextEdit::mouseSelectionMode
1085 Specifies how text should be selected using a mouse.
1088 \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1089 \o TextEdit.SelectWords - The selection is updated with whole words.
1092 This property only applies when \l selectByMouse is true.
1094 QSGTextEdit::SelectionMode QSGTextEdit::mouseSelectionMode() const
1096 Q_D(const QSGTextEdit);
1097 return d->mouseSelectionMode;
1100 void QSGTextEdit::setMouseSelectionMode(SelectionMode mode)
1103 if (d->mouseSelectionMode != mode) {
1104 d->mouseSelectionMode = mode;
1105 d->control->setWordSelectionEnabled(mode == SelectWords);
1106 emit mouseSelectionModeChanged(mode);
1111 \qmlproperty bool QtQuick2::TextEdit::readOnly
1113 Whether the user can interact with the TextEdit item. If this
1114 property is set to true the text cannot be edited by user interaction.
1116 By default this property is false.
1118 void QSGTextEdit::setReadOnly(bool r)
1121 if (r == isReadOnly())
1124 setFlag(QSGItem::ItemAcceptsInputMethod, !r);
1125 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1126 if (d->selectByMouse)
1127 flags = flags | Qt::TextSelectableByMouse;
1129 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1130 d->control->setTextInteractionFlags(flags);
1132 d->control->moveCursor(QTextCursor::End);
1134 emit readOnlyChanged(r);
1137 bool QSGTextEdit::isReadOnly() const
1139 Q_D(const QSGTextEdit);
1140 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1144 Sets how the text edit should interact with user input to the given
1147 void QSGTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1150 d->control->setTextInteractionFlags(flags);
1154 Returns the flags specifying how the text edit should interact
1157 Qt::TextInteractionFlags QSGTextEdit::textInteractionFlags() const
1159 Q_D(const QSGTextEdit);
1160 return d->control->textInteractionFlags();
1164 \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle
1166 The rectangle where the text cursor is rendered
1167 within the text edit. Read-only.
1169 QRect QSGTextEdit::cursorRectangle() const
1171 Q_D(const QSGTextEdit);
1172 return d->control->cursorRect().toRect().translated(0,d->yoff);
1175 bool QSGTextEdit::event(QEvent *event)
1178 if (event->type() == QEvent::ShortcutOverride) {
1179 d->control->processEvent(event, QPointF(0, -d->yoff));
1180 return event->isAccepted();
1182 return QSGImplicitSizeItem::event(event);
1187 Handles the given key \a event.
1189 void QSGTextEdit::keyPressEvent(QKeyEvent *event)
1192 d->control->processEvent(event, QPointF(0, -d->yoff));
1193 if (!event->isAccepted())
1194 QSGImplicitSizeItem::keyPressEvent(event);
1199 Handles the given key \a event.
1201 void QSGTextEdit::keyReleaseEvent(QKeyEvent *event)
1204 d->control->processEvent(event, QPointF(0, -d->yoff));
1205 if (!event->isAccepted())
1206 QSGImplicitSizeItem::keyReleaseEvent(event);
1210 \qmlmethod void QtQuick2::TextEdit::deselect()
1212 Removes active text selection.
1214 void QSGTextEdit::deselect()
1217 QTextCursor c = d->control->textCursor();
1219 d->control->setTextCursor(c);
1223 \qmlmethod void QtQuick2::TextEdit::selectAll()
1225 Causes all text to be selected.
1227 void QSGTextEdit::selectAll()
1230 d->control->selectAll();
1234 \qmlmethod void QtQuick2::TextEdit::selectWord()
1236 Causes the word closest to the current cursor position to be selected.
1238 void QSGTextEdit::selectWord()
1241 QTextCursor c = d->control->textCursor();
1242 c.select(QTextCursor::WordUnderCursor);
1243 d->control->setTextCursor(c);
1247 \qmlmethod void QtQuick2::TextEdit::select(int start, int end)
1249 Causes the text from \a start to \a end to be selected.
1251 If either start or end is out of range, the selection is not changed.
1253 After calling this, selectionStart will become the lesser
1254 and selectionEnd will become the greater (regardless of the order passed
1257 \sa selectionStart, selectionEnd
1259 void QSGTextEdit::select(int start, int end)
1262 if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
1264 QTextCursor cursor = d->control->textCursor();
1265 cursor.beginEditBlock();
1266 cursor.setPosition(start, QTextCursor::MoveAnchor);
1267 cursor.setPosition(end, QTextCursor::KeepAnchor);
1268 cursor.endEditBlock();
1269 d->control->setTextCursor(cursor);
1272 updateSelectionMarkers();
1276 \qmlmethod void QtQuick2::TextEdit::isRightToLeft(int start, int end)
1278 Returns true if the natural reading direction of the editor text
1279 found between positions \a start and \a end is right to left.
1281 bool QSGTextEdit::isRightToLeft(int start, int end)
1285 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1288 return d->text.mid(start, end - start).isRightToLeft();
1292 #ifndef QT_NO_CLIPBOARD
1294 \qmlmethod QtQuick2::TextEdit::cut()
1296 Moves the currently selected text to the system clipboard.
1298 void QSGTextEdit::cut()
1305 \qmlmethod QtQuick2::TextEdit::copy()
1307 Copies the currently selected text to the system clipboard.
1309 void QSGTextEdit::copy()
1316 \qmlmethod QtQuick2::TextEdit::paste()
1318 Replaces the currently selected text by the contents of the system clipboard.
1320 void QSGTextEdit::paste()
1323 d->control->paste();
1325 #endif // QT_NO_CLIPBOARD
1329 Handles the given mouse \a event.
1331 void QSGTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
1334 if (d->focusOnPress){
1335 bool hadActiveFocus = hasActiveFocus();
1337 if (d->showInputPanelOnFocus) {
1338 if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1339 // re-open input panel on press if already focused
1340 openSoftwareInputPanel();
1342 } else { // show input panel on click
1343 if (hasActiveFocus() && !hadActiveFocus) {
1344 d->clickCausedFocus = true;
1348 d->control->processEvent(event, QPointF(0, -d->yoff));
1349 if (!event->isAccepted())
1350 QSGImplicitSizeItem::mousePressEvent(event);
1355 Handles the given mouse \a event.
1357 void QSGTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1360 d->control->processEvent(event, QPointF(0, -d->yoff));
1361 if (!d->showInputPanelOnFocus) { // input panel on click
1362 if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1363 if (canvas() && canvas() == qApp->focusWidget()) {
1364 qt_widget_private(canvas())->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1368 d->clickCausedFocus = false;
1370 if (!event->isAccepted())
1371 QSGImplicitSizeItem::mouseReleaseEvent(event);
1376 Handles the given mouse \a event.
1378 void QSGTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1381 d->control->processEvent(event, QPointF(0, -d->yoff));
1382 if (!event->isAccepted())
1383 QSGImplicitSizeItem::mouseDoubleClickEvent(event);
1388 Handles the given mouse \a event.
1390 void QSGTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1393 d->control->processEvent(event, QPointF(0, -d->yoff));
1394 if (!event->isAccepted())
1395 QSGImplicitSizeItem::mouseMoveEvent(event);
1400 Handles the given input method \a event.
1402 void QSGTextEdit::inputMethodEvent(QInputMethodEvent *event)
1405 const bool wasComposing = isInputMethodComposing();
1406 d->control->processEvent(event, QPointF(0, -d->yoff));
1407 if (wasComposing != isInputMethodComposing())
1408 emit inputMethodComposingChanged();
1411 void QSGTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1414 if (change == ItemActiveFocusHasChanged) {
1415 setCursorVisible(value.boolValue && d->canvas && d->canvas->hasFocus());
1417 QSGItem::itemChange(change, value);
1422 Returns the value of the given \a property.
1424 QVariant QSGTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1426 Q_D(const QSGTextEdit);
1427 return d->control->inputMethodQuery(property);
1430 void QSGTextEdit::updateImageCache(const QRectF &)
1434 // Do we really need the image cache?
1435 if (!d->richText || !d->isComplexRichText) {
1436 if (!d->pixmapCache.isNull())
1437 d->pixmapCache = QPixmap();
1441 if (width() != d->pixmapCache.width() || height() != d->pixmapCache.height())
1442 d->pixmapCache = QPixmap(width(), height());
1444 if (d->pixmapCache.isNull())
1447 // ### Use supplied rect, clear area and update only this part (for cursor updates)
1448 QRectF bounds = QRectF(0, 0, width(), height());
1449 d->pixmapCache.fill(Qt::transparent);
1451 QPainter painter(&d->pixmapCache);
1453 painter.setRenderHint(QPainter::TextAntialiasing);
1454 painter.translate(0, d->yoff);
1456 d->control->drawContents(&painter, bounds);
1461 QSGNode *QSGTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1463 Q_UNUSED(updatePaintNodeData);
1466 QSGNode *currentNode = oldNode;
1467 if (d->richText && d->isComplexRichText) {
1468 QSGImageNode *node = 0;
1469 if (oldNode == 0 || d->nodeType != QSGTextEditPrivate::NodeIsTexture) {
1471 node = QSGItemPrivate::get(this)->sceneGraphContext()->createImageNode();
1472 d->texture = new QSGPlainTexture();
1473 d->nodeType = QSGTextEditPrivate::NodeIsTexture;
1476 node = static_cast<QSGImageNode *>(oldNode);
1479 qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->pixmapCache.toImage());
1480 node->setTexture(0);
1481 node->setTexture(d->texture);
1483 node->setTargetRect(QRectF(0, 0, d->pixmapCache.width(), d->pixmapCache.height()));
1484 node->setSourceRect(QRectF(0, 0, 1, 1));
1485 node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
1486 node->setVerticalWrapMode(QSGTexture::ClampToEdge);
1487 node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that..
1490 } else if (oldNode == 0 || d->documentDirty) {
1491 d->documentDirty = false;
1493 #if defined(Q_WS_MAC)
1494 // Make sure document is relayouted in the paint node on Mac
1495 // to avoid crashes due to the font engines created in the
1497 d->document->markContentsDirty(0, d->document->characterCount());
1500 QSGTextNode *node = 0;
1501 if (oldNode == 0 || d->nodeType != QSGTextEditPrivate::NodeIsText) {
1503 node = new QSGTextNode(QSGItemPrivate::get(this)->sceneGraphContext());
1504 d->nodeType = QSGTextEditPrivate::NodeIsText;
1507 node = static_cast<QSGTextNode *>(oldNode);
1510 node->deleteContent();
1511 node->setMatrix(QMatrix4x4());
1513 QRectF bounds = boundingRect();
1515 QColor selectionColor = d->control->palette().color(QPalette::Highlight);
1516 QColor selectedTextColor = d->control->palette().color(QPalette::HighlightedText);
1517 node->addTextDocument(bounds.topLeft(), d->document, d->color, QSGText::Normal, QColor(),
1518 selectionColor, selectedTextColor, selectionStart(),
1521 #if defined(Q_WS_MAC)
1522 // We also need to make sure the document layout is redone when
1523 // control is returned to the main thread, as all the font engines
1524 // are now owned by the rendering thread
1525 d->document->markContentsDirty(0, d->document->characterCount());
1529 if (d->nodeType == QSGTextEditPrivate::NodeIsText && d->cursorComponent == 0 && !isReadOnly()) {
1530 QSGTextNode *node = static_cast<QSGTextNode *>(currentNode);
1532 QColor color = (!d->cursorVisible || !d->control->cursorOn())
1533 ? QColor(0, 0, 0, 0)
1536 if (node->cursorNode() == 0) {
1537 node->setCursor(cursorRectangle(), color);
1539 node->cursorNode()->setRect(cursorRectangle());
1540 node->cursorNode()->setColor(color);
1549 \qmlproperty bool QtQuick2::TextEdit::smooth
1551 This property holds whether the text is smoothly scaled or transformed.
1553 Smooth filtering gives better visual quality, but is slower. If
1554 the item is displayed at its natural size, this property has no visual or
1557 \note Generally scaling artifacts are only visible if the item is stationary on
1558 the screen. A common pattern when animating an item is to disable smooth
1559 filtering at the beginning of the animation and reenable it at the conclusion.
1563 \qmlproperty bool QtQuick2::TextEdit::canPaste
1565 Returns true if the TextEdit is writable and the content of the clipboard is
1566 suitable for pasting into the TextEdit.
1568 bool QSGTextEdit::canPaste() const
1570 Q_D(const QSGTextEdit);
1575 \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1578 This property holds whether the TextEdit has partial text input from an
1581 While it is composing an input method may rely on mouse or key events from
1582 the TextEdit to edit or commit the partial text. This property can be used
1583 to determine when to disable events handlers that may interfere with the
1584 correct operation of an input method.
1586 bool QSGTextEdit::isInputMethodComposing() const
1588 Q_D(const QSGTextEdit);
1589 if (QTextLayout *layout = d->control->textCursor().block().layout())
1590 return layout->preeditAreaText().length() > 0;
1594 void QSGTextEditPrivate::init()
1598 q->setSmooth(smooth);
1599 q->setAcceptedMouseButtons(Qt::LeftButton);
1600 q->setFlag(QSGItem::ItemAcceptsInputMethod);
1601 q->setFlag(QSGItem::ItemHasContents);
1603 control = new QTextControl(q);
1604 control->setIgnoreUnusedNavigationEvents(true);
1605 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1606 control->setDragEnabled(false);
1608 // By default, QTextControl will issue both a updateCursorRequest() and an updateRequest()
1609 // when the cursor needs to be repainted. We need the signals to be separate to be able to
1610 // distinguish the cursor updates so that we can avoid updating the whole subtree when the
1612 if (!QObject::disconnect(control, SIGNAL(updateCursorRequest(QRectF)),
1613 control, SIGNAL(updateRequest(QRectF)))) {
1614 qWarning("QSGTextEditPrivate::init: Failed to disconnect updateCursorRequest and updateRequest");
1617 // QTextControl follows the default text color
1618 // defined by the platform, declarative text
1619 // should be black by default
1620 QPalette pal = control->palette();
1621 if (pal.color(QPalette::Text) != color) {
1622 pal.setColor(QPalette::Text, color);
1623 control->setPalette(pal);
1626 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateDocument()));
1627 QObject::connect(control, SIGNAL(updateCursorRequest()), q, SLOT(updateCursor()));
1628 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1629 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1630 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1631 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1632 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1633 QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate()));
1634 QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1635 #ifndef QT_NO_CLIPBOARD
1636 QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged()));
1637 QObject::connect(QApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1638 canPaste = control->canPaste();
1641 document = control->document();
1642 document->setDefaultFont(font);
1643 document->setDocumentMargin(textMargin);
1644 document->setUndoRedoEnabled(false); // flush undo buffer.
1645 document->setUndoRedoEnabled(true);
1646 updateDefaultTextOption();
1649 void QSGTextEdit::q_textChanged()
1653 d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
1654 d->determineHorizontalAlignment();
1655 d->updateDefaultTextOption();
1658 emit textChanged(d->text);
1661 void QSGTextEdit::moveCursorDelegate()
1665 emit cursorRectangleChanged();
1668 QRectF cursorRect = cursorRectangle();
1669 d->cursor->setX(cursorRect.x());
1670 d->cursor->setY(cursorRect.y());
1673 void QSGTextEditPrivate::updateSelection()
1676 QTextCursor cursor = control->textCursor();
1677 bool startChange = (lastSelectionStart != cursor.selectionStart());
1678 bool endChange = (lastSelectionEnd != cursor.selectionEnd());
1679 cursor.beginEditBlock();
1680 cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
1681 cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
1682 cursor.endEditBlock();
1683 control->setTextCursor(cursor);
1685 q->selectionStartChanged();
1687 q->selectionEndChanged();
1690 void QSGTextEdit::updateSelectionMarkers()
1693 if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
1694 d->lastSelectionStart = d->control->textCursor().selectionStart();
1695 emit selectionStartChanged();
1697 if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
1698 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1699 emit selectionEndChanged();
1703 QRectF QSGTextEdit::boundingRect() const
1705 Q_D(const QSGTextEdit);
1706 QRectF r = QSGImplicitSizeItem::boundingRect();
1707 int cursorWidth = 1;
1709 cursorWidth = d->cursor->width();
1710 if(!d->document->isEmpty())
1711 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1713 // Could include font max left/right bearings to either side of rectangle.
1715 r.setRight(r.right() + cursorWidth);
1716 return r.translated(0,d->yoff);
1719 qreal QSGTextEditPrivate::getImplicitWidth() const
1721 Q_Q(const QSGTextEdit);
1722 if (!requireImplicitWidth) {
1723 // We don't calculate implicitWidth unless it is required.
1724 // We need to force a size update now to ensure implicitWidth is calculated
1725 const_cast<QSGTextEditPrivate*>(this)->requireImplicitWidth = true;
1726 const_cast<QSGTextEdit*>(q)->updateSize();
1728 return implicitWidth;
1731 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1732 // need to do all the calculations each time
1733 void QSGTextEdit::updateSize()
1736 if (isComponentComplete()) {
1737 qreal naturalWidth = d->implicitWidth;
1738 // ### assumes that if the width is set, the text will fill to edges
1739 // ### (unless wrap is false, then clipping will occur)
1741 if (!d->requireImplicitWidth) {
1742 emit implicitWidthChanged();
1743 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1744 if (d->requireImplicitWidth)
1747 if (d->requireImplicitWidth) {
1748 d->document->setTextWidth(-1);
1749 naturalWidth = d->document->idealWidth();
1751 if (d->document->textWidth() != width())
1752 d->document->setTextWidth(width());
1754 d->document->setTextWidth(-1);
1756 QFontMetrics fm = QFontMetrics(d->font);
1758 dy -= (int)d->document->size().height();
1761 if (heightValid()) {
1762 if (d->vAlign == AlignBottom)
1764 else if (d->vAlign == AlignVCenter)
1771 if (nyoff != d->yoff)
1773 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1775 //### need to comfirm cost of always setting these
1776 int newWidth = qCeil(d->document->idealWidth());
1777 if (!widthValid() && d->document->textWidth() != newWidth)
1778 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1779 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1781 setImplicitWidth(newWidth);
1782 else if (d->requireImplicitWidth)
1783 setImplicitWidth(naturalWidth);
1784 qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
1785 setImplicitHeight(newHeight);
1787 d->paintedSize = QSize(newWidth, newHeight);
1788 emit paintedSizeChanged();
1795 void QSGTextEdit::updateDocument()
1798 d->documentDirty = true;
1800 if (isComponentComplete()) {
1806 void QSGTextEdit::updateCursor()
1809 if (isComponentComplete()) {
1810 updateImageCache(d->control->cursorRect());
1815 void QSGTextEdit::updateTotalLines()
1821 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1822 QTextLayout *layout = it.layout();
1825 subLines += layout->lineCount()-1;
1828 int newTotalLines = d->document->lineCount() + subLines;
1829 if (d->lineCount != newTotalLines) {
1830 d->lineCount = newTotalLines;
1831 emit lineCountChanged();
1835 void QSGTextEditPrivate::updateDefaultTextOption()
1838 QTextOption opt = document->defaultTextOption();
1839 int oldAlignment = opt.alignment();
1841 QSGTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
1842 if (rightToLeftText) {
1843 if (horizontalAlignment == QSGTextEdit::AlignLeft)
1844 horizontalAlignment = QSGTextEdit::AlignRight;
1845 else if (horizontalAlignment == QSGTextEdit::AlignRight)
1846 horizontalAlignment = QSGTextEdit::AlignLeft;
1848 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
1850 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1851 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
1853 bool oldUseDesignMetrics = opt.useDesignMetrics();
1854 bool useDesignMetrics = !qmlDisableDistanceField();
1855 opt.setUseDesignMetrics(useDesignMetrics);
1857 if (oldWrapMode == opt.wrapMode()
1858 && oldAlignment == opt.alignment()
1859 && oldUseDesignMetrics == useDesignMetrics) {
1862 document->setDefaultTextOption(opt);
1868 \qmlmethod void QtQuick2::TextEdit::openSoftwareInputPanel()
1870 Opens software input panels like virtual keyboards for typing, useful for
1871 customizing when you want the input keyboard to be shown and hidden in
1874 By default the opening of input panels follows the platform style. On Symbian^1 and
1875 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1876 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1877 always closed if no editor has active focus.
1879 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1880 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1881 the behavior you want.
1883 Only relevant on platforms, which provide virtual keyboards.
1889 text: "Hello world!"
1890 activeFocusOnPress: false
1892 anchors.fill: parent
1894 if (!textEdit.activeFocus) {
1895 textEdit.forceActiveFocus();
1896 textEdit.openSoftwareInputPanel();
1898 textEdit.focus = false;
1901 onPressAndHold: textEdit.closeSoftwareInputPanel();
1906 void QSGTextEdit::openSoftwareInputPanel()
1909 if (canvas() && canvas() == qApp->focusWidget()) {
1910 QEvent event(QEvent::RequestSoftwareInputPanel);
1911 QApplication::sendEvent(canvas(), &event);
1917 \qmlmethod void QtQuick2::TextEdit::closeSoftwareInputPanel()
1919 Closes a software input panel like a virtual keyboard shown on the screen, useful
1920 for customizing when you want the input keyboard to be shown and hidden in
1923 By default the opening of input panels follows the platform style. On Symbian^1 and
1924 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1925 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1926 always closed if no editor has active focus.
1928 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1929 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1930 the behavior you want.
1932 Only relevant on platforms, which provide virtual keyboards.
1938 text: "Hello world!"
1939 activeFocusOnPress: false
1941 anchors.fill: parent
1943 if (!textEdit.activeFocus) {
1944 textEdit.forceActiveFocus();
1945 textEdit.openSoftwareInputPanel();
1947 textEdit.focus = false;
1950 onPressAndHold: textEdit.closeSoftwareInputPanel();
1955 void QSGTextEdit::closeSoftwareInputPanel()
1958 if (canvas() && canvas() == qApp->focusWidget()) {
1959 QEvent event(QEvent::CloseSoftwareInputPanel);
1960 QApplication::sendEvent(canvas(), &event);
1965 void QSGTextEdit::focusInEvent(QFocusEvent *event)
1967 Q_D(const QSGTextEdit);
1968 if (d->showInputPanelOnFocus) {
1969 if (d->focusOnPress && !isReadOnly()) {
1970 openSoftwareInputPanel();
1973 QSGImplicitSizeItem::focusInEvent(event);
1976 void QSGTextEdit::q_canPasteChanged()
1979 bool old = d->canPaste;
1980 d->canPaste = d->control->canPaste();
1981 if(old!=d->canPaste)
1982 emit canPasteChanged();