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 "qquicktextedit_p.h"
43 #include "qquicktextedit_p_p.h"
44 #include "qquickevents_p_p.h"
45 #include "qquickcanvas.h"
46 #include "qquicktextnode_p.h"
47 #include "qsgsimplerectnode.h"
49 #include <QtDeclarative/qdeclarativeinfo.h>
50 #include <QtGui/qguiapplication.h>
51 #include <QtGui/qevent.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/qsgdistancefieldglyphcache_p.h>
60 #include <private/qsgtexture_p.h>
61 #include <private/qsgadaptationlayer_p.h>
65 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
66 DEFINE_BOOL_CONFIG_OPTION(qmlEnableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE)
69 \qmlclass TextEdit QQuickTextEdit
70 \inqmlmodule QtQuick 2
71 \ingroup qml-basic-visual-elements
72 \brief The TextEdit item displays multiple lines of editable formatted text.
75 The TextEdit item displays a block of editable, formatted text.
77 It can display both plain and rich text. For example:
82 text: "<b>Hello</b> <i>World!</i>"
83 font.family: "Helvetica"
90 \image declarative-textedit.gif
92 Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
94 Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
95 to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
97 \snippet snippets/declarative/texteditor.qml 0
99 A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible
100 scrollbar, or a scrollbar that fades in to show location, etc.
102 Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
103 be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
104 from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
106 You can translate between cursor positions (characters from the start of the document) and pixel
107 points using positionAt() and positionToRectangle().
109 \sa Text, TextInput, {declarative/text/textselection}{Text Selection example}
113 \qmlsignal QtQuick2::TextEdit::onLinkActivated(string link)
115 This handler is called when the user clicks on a link embedded in the text.
116 The link must be in rich text or HTML format and the
117 \a link string provides access to the particular link.
119 QQuickTextEdit::QQuickTextEdit(QQuickItem *parent)
120 : QQuickImplicitSizeItem(*(new QQuickTextEditPrivate), parent)
126 QString QQuickTextEdit::text() const
128 Q_D(const QQuickTextEdit);
130 #ifndef QT_NO_TEXTHTMLPARSER
132 return d->document->toHtml();
135 return d->document->toPlainText();
139 \qmlproperty string QtQuick2::TextEdit::font.family
141 Sets the family name of the font.
143 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
144 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
145 If the family isn't available a family will be set using the font matching algorithm.
149 \qmlproperty bool QtQuick2::TextEdit::font.bold
151 Sets whether the font weight is bold.
155 \qmlproperty enumeration QtQuick2::TextEdit::font.weight
157 Sets the font's weight.
159 The weight can be one of:
162 \o Font.Normal - the default
169 TextEdit { text: "Hello"; font.weight: Font.DemiBold }
174 \qmlproperty bool QtQuick2::TextEdit::font.italic
176 Sets whether the font has an italic style.
180 \qmlproperty bool QtQuick2::TextEdit::font.underline
182 Sets whether the text is underlined.
186 \qmlproperty bool QtQuick2::TextEdit::font.strikeout
188 Sets whether the font has a strikeout style.
192 \qmlproperty real QtQuick2::TextEdit::font.pointSize
194 Sets the font size in points. The point size must be greater than zero.
198 \qmlproperty int QtQuick2::TextEdit::font.pixelSize
200 Sets the font size in pixels.
202 Using this function makes the font device dependent. Use
203 \l{TextEdit::font.pointSize} to set the size of the font in a
204 device independent manner.
208 \qmlproperty real QtQuick2::TextEdit::font.letterSpacing
210 Sets the letter spacing for the font.
212 Letter spacing changes the default spacing between individual letters in the font.
213 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
217 \qmlproperty real QtQuick2::TextEdit::font.wordSpacing
219 Sets the word spacing for the font.
221 Word spacing changes the default spacing between individual words.
222 A positive value increases the word spacing by a corresponding amount of pixels,
223 while a negative value decreases the inter-word spacing accordingly.
227 \qmlproperty enumeration QtQuick2::TextEdit::font.capitalization
229 Sets the capitalization for the text.
232 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
233 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
234 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
235 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
236 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
240 TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
245 \qmlproperty string QtQuick2::TextEdit::text
247 The text to display. If the text format is AutoText the text edit will
248 automatically determine whether the text should be treated as
249 rich text. This determination is made using Qt::mightBeRichText().
251 void QQuickTextEdit::setText(const QString &text)
254 if (QQuickTextEdit::text() == text)
257 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
259 #ifndef QT_NO_TEXTHTMLPARSER
260 d->control->setHtml(text);
262 d->control->setPlainText(text);
264 d->useImageFallback = qmlEnableImageCache();
266 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.AutoText. 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)
321 bool wasRich = d->richText;
322 d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
324 if (wasRich && !d->richText) {
325 d->control->setPlainText(d->text);
327 } else if (!wasRich && d->richText) {
328 #ifndef QT_NO_TEXTHTMLPARSER
329 d->control->setHtml(d->text);
331 d->control->setPlainText(d->text);
334 d->useImageFallback = qmlEnableImageCache();
337 d->control->setAcceptRichText(d->format != PlainText);
338 emit textFormatChanged(d->format);
341 QFont QQuickTextEdit::font() const
343 Q_D(const QQuickTextEdit);
344 return d->sourceFont;
347 void QQuickTextEdit::setFont(const QFont &font)
350 if (d->sourceFont == font)
353 d->sourceFont = font;
354 QFont oldFont = d->font;
356 if (d->font.pointSizeF() != -1) {
358 qreal size = qRound(d->font.pointSizeF()*2.0);
359 d->font.setPointSizeF(size/2.0);
362 if (oldFont != d->font) {
363 d->document->setDefaultFont(d->font);
365 d->cursor->setHeight(QFontMetrics(d->font).height());
366 moveCursorDelegate();
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()) {
553 bool alignToRight = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
554 return setHAlign(alignToRight ? QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft);
559 void QQuickTextEditPrivate::mirrorChange()
562 if (q->isComponentComplete()) {
563 if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) {
564 updateDefaultTextOption();
566 emit q->effectiveHorizontalAlignmentChanged();
571 QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const
573 Q_D(const QQuickTextEdit);
577 void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment)
580 if (alignment == d->vAlign)
582 d->vAlign = alignment;
583 d->updateDefaultTextOption();
585 moveCursorDelegate();
586 emit verticalAlignmentChanged(d->vAlign);
589 \qmlproperty enumeration QtQuick2::TextEdit::wrapMode
591 Set this property to wrap the text to the TextEdit item's width.
592 The text will only wrap if an explicit width has been set.
595 \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
596 \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
597 \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
598 \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.
601 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
603 QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode() const
605 Q_D(const QQuickTextEdit);
609 void QQuickTextEdit::setWrapMode(WrapMode mode)
612 if (mode == d->wrapMode)
615 d->updateDefaultTextOption();
617 emit wrapModeChanged();
621 \qmlproperty int QtQuick2::TextEdit::lineCount
623 Returns the total number of lines in the textEdit item.
625 int QQuickTextEdit::lineCount() const
627 Q_D(const QQuickTextEdit);
632 \qmlproperty real QtQuick2::TextEdit::paintedWidth
634 Returns the width of the text, including the width past the width
635 which is covered due to insufficient wrapping if \l wrapMode is set.
637 qreal QQuickTextEdit::paintedWidth() const
639 Q_D(const QQuickTextEdit);
640 return d->paintedSize.width();
644 \qmlproperty real QtQuick2::TextEdit::paintedHeight
646 Returns the height of the text, including the height past the height
647 that is covered if the text does not fit within the set height.
649 qreal QQuickTextEdit::paintedHeight() const
651 Q_D(const QQuickTextEdit);
652 return d->paintedSize.height();
656 \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position)
658 Returns the rectangle at the given \a position in the text. The x, y,
659 and height properties correspond to the cursor that would describe
662 QRectF QQuickTextEdit::positionToRectangle(int pos) const
664 Q_D(const QQuickTextEdit);
665 QTextCursor c(d->document);
667 return d->control->cursorRect(c);
672 \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y)
674 Returns the text position closest to pixel position (\a x, \a y).
676 Position 0 is before the first character, position 1 is after the first character
677 but before the second, and so on until position \l {text}.length, which is after all characters.
679 int QQuickTextEdit::positionAt(int x, int y) const
681 Q_D(const QQuickTextEdit);
682 int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
683 QTextCursor cursor = d->control->textCursor();
684 if (r > cursor.position()) {
685 // The cursor position includes positions within the preedit text, but only positions in the
686 // same text block are offset so it is possible to get a position that is either part of the
687 // preedit or the next text block.
688 QTextLayout *layout = cursor.block().layout();
689 const int preeditLength = layout
690 ? layout->preeditAreaText().length()
692 if (preeditLength > 0
693 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
694 r = r > cursor.position() + preeditLength
703 \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
705 Moves the cursor to \a position and updates the selection according to the optional \a mode
706 parameter. (To only move the cursor, set the \l cursorPosition property.)
708 When this method is called it additionally sets either the
709 selectionStart or the selectionEnd (whichever was at the previous cursor position)
710 to the specified position. This allows you to easily extend and contract the selected
713 The selection mode specifies whether the selection is updated on a per character or a per word
714 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
717 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
718 the previous cursor position) to the specified position.
719 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
720 words between the specified postion and the previous cursor position. Words partially in the
724 For example, take this sequence of calls:
728 moveCursorSelection(9, TextEdit.SelectCharacters)
729 moveCursorSelection(7, TextEdit.SelectCharacters)
732 This moves the cursor to position 5, extend the selection end from 5 to 9
733 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
734 selected (the 6th and 7th characters).
736 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
737 before or on position 5 and extend the selection end to a word boundary on or past position 9.
739 void QQuickTextEdit::moveCursorSelection(int pos)
741 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
743 QTextCursor cursor = d->control->textCursor();
744 if (cursor.position() == pos)
746 cursor.setPosition(pos, QTextCursor::KeepAnchor);
747 d->control->setTextCursor(cursor);
750 void QQuickTextEdit::moveCursorSelection(int pos, SelectionMode mode)
753 QTextCursor cursor = d->control->textCursor();
754 if (cursor.position() == pos)
756 if (mode == SelectCharacters) {
757 cursor.setPosition(pos, QTextCursor::KeepAnchor);
758 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
759 if (cursor.anchor() > cursor.position()) {
760 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
761 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
762 if (cursor.position() == cursor.anchor())
763 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
765 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
767 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
768 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
771 cursor.setPosition(pos, QTextCursor::KeepAnchor);
772 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
773 if (cursor.position() != pos)
774 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
775 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
776 if (cursor.anchor() < cursor.position()) {
777 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
778 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
780 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
781 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
782 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
783 if (cursor.position() != cursor.anchor()) {
784 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
785 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
789 cursor.setPosition(pos, QTextCursor::KeepAnchor);
790 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
791 if (cursor.position() != pos) {
792 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
793 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
796 d->control->setTextCursor(cursor);
800 \qmlproperty bool QtQuick2::TextEdit::cursorVisible
801 If true the text edit shows a cursor.
803 This property is set and unset when the text edit gets active focus, but it can also
804 be set directly (useful, for example, if a KeyProxy might forward keys to it).
806 bool QQuickTextEdit::isCursorVisible() const
808 Q_D(const QQuickTextEdit);
809 return d->cursorVisible;
812 void QQuickTextEdit::setCursorVisible(bool on)
815 if (d->cursorVisible == on)
817 d->cursorVisible = on;
818 QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
819 if (!on && !d->persistentSelection)
820 d->control->setCursorIsFocusIndicator(true);
821 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
822 emit cursorVisibleChanged(d->cursorVisible);
826 \qmlproperty int QtQuick2::TextEdit::cursorPosition
827 The position of the cursor in the TextEdit.
829 int QQuickTextEdit::cursorPosition() const
831 Q_D(const QQuickTextEdit);
832 return d->control->textCursor().position();
835 void QQuickTextEdit::setCursorPosition(int pos)
838 if (pos < 0 || pos > d->text.length())
840 QTextCursor cursor = d->control->textCursor();
841 if (cursor.position() == pos && cursor.anchor() == pos)
843 cursor.setPosition(pos);
844 d->control->setTextCursor(cursor);
848 \qmlproperty Component QtQuick2::TextEdit::cursorDelegate
849 The delegate for the cursor in the TextEdit.
851 If you set a cursorDelegate for a TextEdit, this delegate will be used for
852 drawing the cursor instead of the standard cursor. An instance of the
853 delegate will be created and managed by the text edit when a cursor is
854 needed, and the x and y properties of delegate instance will be set so as
855 to be one pixel before the top left of the current character.
857 Note that the root item of the delegate component must be a QDeclarativeItem or
858 QDeclarativeItem derived item.
860 QDeclarativeComponent* QQuickTextEdit::cursorDelegate() const
862 Q_D(const QQuickTextEdit);
863 return d->cursorComponent;
866 void QQuickTextEdit::setCursorDelegate(QDeclarativeComponent* c)
869 if (d->cursorComponent) {
871 d->control->setCursorWidth(-1);
877 d->cursorComponent = c;
878 if (c && c->isReady()) {
879 loadCursorDelegate();
882 connect(c, SIGNAL(statusChanged()),
883 this, SLOT(loadCursorDelegate()));
886 emit cursorDelegateChanged();
889 void QQuickTextEdit::loadCursorDelegate()
892 if (d->cursorComponent->isLoading())
894 QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
895 QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
896 d->cursor = qobject_cast<QQuickItem*>(object);
898 d->control->setCursorWidth(0);
900 QDeclarative_setParent_noEvent(d->cursor, this);
901 d->cursor->setParentItem(this);
902 d->cursor->setHeight(QFontMetrics(d->font).height());
903 moveCursorDelegate();
906 qmlInfo(this) << "Error loading cursor delegate.";
911 \qmlproperty int QtQuick2::TextEdit::selectionStart
913 The cursor position before the first character in the current selection.
915 This property is read-only. To change the selection, use select(start,end),
916 selectAll(), or selectWord().
918 \sa selectionEnd, cursorPosition, selectedText
920 int QQuickTextEdit::selectionStart() const
922 Q_D(const QQuickTextEdit);
923 return d->control->textCursor().selectionStart();
927 \qmlproperty int QtQuick2::TextEdit::selectionEnd
929 The cursor position after the last character in the current selection.
931 This property is read-only. To change the selection, use select(start,end),
932 selectAll(), or selectWord().
934 \sa selectionStart, cursorPosition, selectedText
936 int QQuickTextEdit::selectionEnd() const
938 Q_D(const QQuickTextEdit);
939 return d->control->textCursor().selectionEnd();
943 \qmlproperty string QtQuick2::TextEdit::selectedText
945 This read-only property provides the text currently selected in the
948 It is equivalent to the following snippet, but is faster and easier
951 //myTextEdit is the id of the TextEdit
952 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
953 myTextEdit.selectionEnd);
956 QString QQuickTextEdit::selectedText() const
958 Q_D(const QQuickTextEdit);
959 return d->control->textCursor().selectedText();
963 \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress
965 Whether the TextEdit should gain active focus on a mouse press. By default this is
968 bool QQuickTextEdit::focusOnPress() const
970 Q_D(const QQuickTextEdit);
971 return d->focusOnPress;
974 void QQuickTextEdit::setFocusOnPress(bool on)
977 if (d->focusOnPress == on)
979 d->focusOnPress = on;
980 emit activeFocusOnPressChanged(d->focusOnPress);
984 \qmlproperty bool QtQuick2::TextEdit::persistentSelection
986 Whether the TextEdit should keep the selection visible when it loses active focus to another
987 item in the scene. By default this is set to true;
989 bool QQuickTextEdit::persistentSelection() const
991 Q_D(const QQuickTextEdit);
992 return d->persistentSelection;
995 void QQuickTextEdit::setPersistentSelection(bool on)
998 if (d->persistentSelection == on)
1000 d->persistentSelection = on;
1001 emit persistentSelectionChanged(d->persistentSelection);
1005 \qmlproperty real QtQuick2::TextEdit::textMargin
1007 The margin, in pixels, around the text in the TextEdit.
1009 qreal QQuickTextEdit::textMargin() const
1011 Q_D(const QQuickTextEdit);
1012 return d->textMargin;
1015 void QQuickTextEdit::setTextMargin(qreal margin)
1017 Q_D(QQuickTextEdit);
1018 if (d->textMargin == margin)
1020 d->textMargin = margin;
1021 d->document->setDocumentMargin(d->textMargin);
1022 emit textMarginChanged(d->textMargin);
1025 void QQuickTextEdit::geometryChanged(const QRectF &newGeometry,
1026 const QRectF &oldGeometry)
1028 if (newGeometry.width() != oldGeometry.width())
1030 QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1034 Ensures any delayed caching or data loading the class
1035 needs to performed is complete.
1037 void QQuickTextEdit::componentComplete()
1039 Q_D(QQuickTextEdit);
1040 QQuickImplicitSizeItem::componentComplete();
1043 d->useImageFallback = qmlEnableImageCache();
1046 d->determineHorizontalAlignment();
1047 d->updateDefaultTextOption();
1054 \qmlproperty bool QtQuick2::TextEdit::selectByMouse
1058 If true, the user can use the mouse to select text in some
1059 platform-specific way. Note that for some platforms this may
1060 not be an appropriate interaction (eg. may conflict with how
1061 the text needs to behave inside a Flickable.
1063 bool QQuickTextEdit::selectByMouse() const
1065 Q_D(const QQuickTextEdit);
1066 return d->selectByMouse;
1069 void QQuickTextEdit::setSelectByMouse(bool on)
1071 Q_D(QQuickTextEdit);
1072 if (d->selectByMouse != on) {
1073 d->selectByMouse = on;
1074 setKeepMouseGrab(on);
1076 setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1078 setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1079 emit selectByMouseChanged(on);
1084 \qmlproperty enum QtQuick2::TextEdit::mouseSelectionMode
1086 Specifies how text should be selected using a mouse.
1089 \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1090 \o TextEdit.SelectWords - The selection is updated with whole words.
1093 This property only applies when \l selectByMouse is true.
1095 QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode() const
1097 Q_D(const QQuickTextEdit);
1098 return d->mouseSelectionMode;
1101 void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode)
1103 Q_D(QQuickTextEdit);
1104 if (d->mouseSelectionMode != mode) {
1105 d->mouseSelectionMode = mode;
1106 d->control->setWordSelectionEnabled(mode == SelectWords);
1107 emit mouseSelectionModeChanged(mode);
1112 \qmlproperty bool QtQuick2::TextEdit::readOnly
1114 Whether the user can interact with the TextEdit item. If this
1115 property is set to true the text cannot be edited by user interaction.
1117 By default this property is false.
1119 void QQuickTextEdit::setReadOnly(bool r)
1121 Q_D(QQuickTextEdit);
1122 if (r == isReadOnly())
1125 setFlag(QQuickItem::ItemAcceptsInputMethod, !r);
1126 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1127 if (d->selectByMouse)
1128 flags = flags | Qt::TextSelectableByMouse;
1130 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1131 d->control->setTextInteractionFlags(flags);
1133 d->control->moveCursor(QTextCursor::End);
1135 emit readOnlyChanged(r);
1138 bool QQuickTextEdit::isReadOnly() const
1140 Q_D(const QQuickTextEdit);
1141 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1145 Sets how the text edit should interact with user input to the given
1148 void QQuickTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1150 Q_D(QQuickTextEdit);
1151 d->control->setTextInteractionFlags(flags);
1155 Returns the flags specifying how the text edit should interact
1158 Qt::TextInteractionFlags QQuickTextEdit::textInteractionFlags() const
1160 Q_D(const QQuickTextEdit);
1161 return d->control->textInteractionFlags();
1165 \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle
1167 The rectangle where the text cursor is rendered
1168 within the text edit. Read-only.
1170 QRect QQuickTextEdit::cursorRectangle() const
1172 Q_D(const QQuickTextEdit);
1173 return d->control->cursorRect().toRect().translated(0,d->yoff);
1176 bool QQuickTextEdit::event(QEvent *event)
1178 Q_D(QQuickTextEdit);
1179 if (event->type() == QEvent::ShortcutOverride) {
1180 d->control->processEvent(event, QPointF(0, -d->yoff));
1181 return event->isAccepted();
1183 return QQuickImplicitSizeItem::event(event);
1188 Handles the given key \a event.
1190 void QQuickTextEdit::keyPressEvent(QKeyEvent *event)
1192 Q_D(QQuickTextEdit);
1193 d->control->processEvent(event, QPointF(0, -d->yoff));
1194 if (!event->isAccepted())
1195 QQuickImplicitSizeItem::keyPressEvent(event);
1200 Handles the given key \a event.
1202 void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event)
1204 Q_D(QQuickTextEdit);
1205 d->control->processEvent(event, QPointF(0, -d->yoff));
1206 if (!event->isAccepted())
1207 QQuickImplicitSizeItem::keyReleaseEvent(event);
1211 \qmlmethod void QtQuick2::TextEdit::deselect()
1213 Removes active text selection.
1215 void QQuickTextEdit::deselect()
1217 Q_D(QQuickTextEdit);
1218 QTextCursor c = d->control->textCursor();
1220 d->control->setTextCursor(c);
1224 \qmlmethod void QtQuick2::TextEdit::selectAll()
1226 Causes all text to be selected.
1228 void QQuickTextEdit::selectAll()
1230 Q_D(QQuickTextEdit);
1231 d->control->selectAll();
1235 \qmlmethod void QtQuick2::TextEdit::selectWord()
1237 Causes the word closest to the current cursor position to be selected.
1239 void QQuickTextEdit::selectWord()
1241 Q_D(QQuickTextEdit);
1242 QTextCursor c = d->control->textCursor();
1243 c.select(QTextCursor::WordUnderCursor);
1244 d->control->setTextCursor(c);
1248 \qmlmethod void QtQuick2::TextEdit::select(int start, int end)
1250 Causes the text from \a start to \a end to be selected.
1252 If either start or end is out of range, the selection is not changed.
1254 After calling this, selectionStart will become the lesser
1255 and selectionEnd will become the greater (regardless of the order passed
1258 \sa selectionStart, selectionEnd
1260 void QQuickTextEdit::select(int start, int end)
1262 Q_D(QQuickTextEdit);
1263 if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
1265 QTextCursor cursor = d->control->textCursor();
1266 cursor.beginEditBlock();
1267 cursor.setPosition(start, QTextCursor::MoveAnchor);
1268 cursor.setPosition(end, QTextCursor::KeepAnchor);
1269 cursor.endEditBlock();
1270 d->control->setTextCursor(cursor);
1273 updateSelectionMarkers();
1277 \qmlmethod void QtQuick2::TextEdit::isRightToLeft(int start, int end)
1279 Returns true if the natural reading direction of the editor text
1280 found between positions \a start and \a end is right to left.
1282 bool QQuickTextEdit::isRightToLeft(int start, int end)
1284 Q_D(QQuickTextEdit);
1286 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1289 return d->text.mid(start, end - start).isRightToLeft();
1293 #ifndef QT_NO_CLIPBOARD
1295 \qmlmethod QtQuick2::TextEdit::cut()
1297 Moves the currently selected text to the system clipboard.
1299 void QQuickTextEdit::cut()
1301 Q_D(QQuickTextEdit);
1306 \qmlmethod QtQuick2::TextEdit::copy()
1308 Copies the currently selected text to the system clipboard.
1310 void QQuickTextEdit::copy()
1312 Q_D(QQuickTextEdit);
1317 \qmlmethod QtQuick2::TextEdit::paste()
1319 Replaces the currently selected text by the contents of the system clipboard.
1321 void QQuickTextEdit::paste()
1323 Q_D(QQuickTextEdit);
1324 d->control->paste();
1326 #endif // QT_NO_CLIPBOARD
1330 Handles the given mouse \a event.
1332 void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
1334 Q_D(QQuickTextEdit);
1335 if (d->focusOnPress){
1336 bool hadActiveFocus = hasActiveFocus();
1338 // re-open input panel on press if already focused
1339 if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
1340 openSoftwareInputPanel();
1342 d->control->processEvent(event, QPointF(0, -d->yoff));
1343 if (!event->isAccepted())
1344 QQuickImplicitSizeItem::mousePressEvent(event);
1349 Handles the given mouse \a event.
1351 void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
1353 Q_D(QQuickTextEdit);
1354 d->control->processEvent(event, QPointF(0, -d->yoff));
1356 if (!event->isAccepted())
1357 QQuickImplicitSizeItem::mouseReleaseEvent(event);
1362 Handles the given mouse \a event.
1364 void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
1366 Q_D(QQuickTextEdit);
1367 d->control->processEvent(event, QPointF(0, -d->yoff));
1368 if (!event->isAccepted())
1369 QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1374 Handles the given mouse \a event.
1376 void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
1378 Q_D(QQuickTextEdit);
1379 d->control->processEvent(event, QPointF(0, -d->yoff));
1380 if (!event->isAccepted())
1381 QQuickImplicitSizeItem::mouseMoveEvent(event);
1386 Handles the given input method \a event.
1388 void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
1390 Q_D(QQuickTextEdit);
1391 const bool wasComposing = isInputMethodComposing();
1392 d->control->processEvent(event, QPointF(0, -d->yoff));
1393 if (wasComposing != isInputMethodComposing())
1394 emit inputMethodComposingChanged();
1397 void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1399 Q_D(QQuickTextEdit);
1400 if (change == ItemActiveFocusHasChanged) {
1401 setCursorVisible(value.boolValue); // ### refactor: focus handling && d->canvas && d->canvas->hasFocus());
1403 QQuickItem::itemChange(change, value);
1408 Returns the value of the given \a property.
1410 QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1412 Q_D(const QQuickTextEdit);
1417 v = (bool)(flags() & ItemAcceptsInputMethod);
1420 v = (int)inputMethodHints();
1423 v = d->control->inputMethodQuery(property);
1430 void QQuickTextEdit::updateImageCache(const QRectF &)
1432 Q_D(QQuickTextEdit);
1434 // Do we really need the image cache?
1435 if (!d->richText || !d->useImageFallback) {
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 *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1463 Q_UNUSED(updatePaintNodeData);
1464 Q_D(QQuickTextEdit);
1466 QSGNode *currentNode = oldNode;
1467 if (d->richText && d->useImageFallback) {
1468 QSGImageNode *node = 0;
1469 if (oldNode == 0 || d->nodeType != QQuickTextEditPrivate::NodeIsTexture) {
1471 node = QQuickItemPrivate::get(this)->sceneGraphContext()->createImageNode();
1472 d->texture = new QSGPlainTexture();
1473 d->nodeType = QQuickTextEditPrivate::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_OS_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 QQuickTextNode *node = 0;
1501 if (oldNode == 0 || d->nodeType != QQuickTextEditPrivate::NodeIsText) {
1503 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1504 d->nodeType = QQuickTextEditPrivate::NodeIsText;
1507 node = static_cast<QQuickTextNode *>(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, QQuickText::Normal, QColor(),
1518 selectionColor, selectedTextColor, selectionStart(),
1519 selectionEnd() - 1); // selectionEnd() returns first char after
1522 #if defined(Q_OS_MAC)
1523 // We also need to make sure the document layout is redone when
1524 // control is returned to the main thread, as all the font engines
1525 // are now owned by the rendering thread
1526 d->document->markContentsDirty(0, d->document->characterCount());
1530 if (d->nodeType == QQuickTextEditPrivate::NodeIsText && d->cursorComponent == 0 && !isReadOnly()) {
1531 QQuickTextNode *node = static_cast<QQuickTextNode *>(currentNode);
1533 QColor color = (!d->cursorVisible || !d->control->cursorOn())
1534 ? QColor(0, 0, 0, 0)
1537 if (node->cursorNode() == 0) {
1538 node->setCursor(cursorRectangle(), color);
1540 node->cursorNode()->setRect(cursorRectangle());
1541 node->cursorNode()->setColor(color);
1550 \qmlproperty bool QtQuick2::TextEdit::smooth
1552 This property holds whether the text is smoothly scaled or transformed.
1554 Smooth filtering gives better visual quality, but is slower. If
1555 the item is displayed at its natural size, this property has no visual or
1558 \note Generally scaling artifacts are only visible if the item is stationary on
1559 the screen. A common pattern when animating an item is to disable smooth
1560 filtering at the beginning of the animation and reenable it at the conclusion.
1564 \qmlproperty bool QtQuick2::TextEdit::canPaste
1566 Returns true if the TextEdit is writable and the content of the clipboard is
1567 suitable for pasting into the TextEdit.
1569 bool QQuickTextEdit::canPaste() const
1571 Q_D(const QQuickTextEdit);
1576 \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1579 This property holds whether the TextEdit has partial text input from an
1582 While it is composing an input method may rely on mouse or key events from
1583 the TextEdit to edit or commit the partial text. This property can be used
1584 to determine when to disable events handlers that may interfere with the
1585 correct operation of an input method.
1587 bool QQuickTextEdit::isInputMethodComposing() const
1589 Q_D(const QQuickTextEdit);
1590 if (QTextLayout *layout = d->control->textCursor().block().layout())
1591 return layout->preeditAreaText().length() > 0;
1595 void QQuickTextEditPrivate::init()
1597 Q_Q(QQuickTextEdit);
1599 q->setSmooth(smooth);
1600 q->setAcceptedMouseButtons(Qt::LeftButton);
1601 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1602 q->setFlag(QQuickItem::ItemHasContents);
1604 control = new QTextControl(q);
1605 control->setIgnoreUnusedNavigationEvents(true);
1606 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1607 control->setDragEnabled(false);
1609 // By default, QTextControl will issue both a updateCursorRequest() and an updateRequest()
1610 // when the cursor needs to be repainted. We need the signals to be separate to be able to
1611 // distinguish the cursor updates so that we can avoid updating the whole subtree when the
1613 if (!QObject::disconnect(control, SIGNAL(updateCursorRequest(QRectF)),
1614 control, SIGNAL(updateRequest(QRectF)))) {
1615 qWarning("QQuickTextEditPrivate::init: Failed to disconnect updateCursorRequest and updateRequest");
1618 // QTextControl follows the default text color
1619 // defined by the platform, declarative text
1620 // should be black by default
1621 QPalette pal = control->palette();
1622 if (pal.color(QPalette::Text) != color) {
1623 pal.setColor(QPalette::Text, color);
1624 control->setPalette(pal);
1627 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateDocument()));
1628 QObject::connect(control, SIGNAL(updateCursorRequest()), q, SLOT(updateCursor()));
1629 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1630 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1631 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1632 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1633 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1634 QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate()));
1635 QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1636 #ifndef QT_NO_CLIPBOARD
1637 QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged()));
1638 QObject::connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1639 canPaste = control->canPaste();
1642 document = control->document();
1643 document->setDefaultFont(font);
1644 document->setDocumentMargin(textMargin);
1645 document->setUndoRedoEnabled(false); // flush undo buffer.
1646 document->setUndoRedoEnabled(true);
1647 updateDefaultTextOption();
1650 void QQuickTextEdit::q_textChanged()
1652 Q_D(QQuickTextEdit);
1654 d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
1655 d->determineHorizontalAlignment();
1656 d->updateDefaultTextOption();
1659 emit textChanged(d->text);
1662 void QQuickTextEdit::moveCursorDelegate()
1664 Q_D(QQuickTextEdit);
1665 d->determineHorizontalAlignment();
1667 emit cursorRectangleChanged();
1670 QRectF cursorRect = cursorRectangle();
1671 d->cursor->setX(cursorRect.x());
1672 d->cursor->setY(cursorRect.y());
1675 void QQuickTextEditPrivate::updateSelection()
1677 Q_Q(QQuickTextEdit);
1678 QTextCursor cursor = control->textCursor();
1679 bool startChange = (lastSelectionStart != cursor.selectionStart());
1680 bool endChange = (lastSelectionEnd != cursor.selectionEnd());
1681 cursor.beginEditBlock();
1682 cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
1683 cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
1684 cursor.endEditBlock();
1685 control->setTextCursor(cursor);
1687 q->selectionStartChanged();
1689 q->selectionEndChanged();
1692 void QQuickTextEdit::updateSelectionMarkers()
1694 Q_D(QQuickTextEdit);
1695 if (d->lastSelectionStart != d->control->textCursor().selectionStart()) {
1696 d->lastSelectionStart = d->control->textCursor().selectionStart();
1697 emit selectionStartChanged();
1699 if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) {
1700 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1701 emit selectionEndChanged();
1705 QRectF QQuickTextEdit::boundingRect() const
1707 Q_D(const QQuickTextEdit);
1708 QRectF r = QQuickImplicitSizeItem::boundingRect();
1709 int cursorWidth = 1;
1711 cursorWidth = d->cursor->width();
1712 if (!d->document->isEmpty())
1713 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1715 // Could include font max left/right bearings to either side of rectangle.
1717 r.setRight(r.right() + cursorWidth);
1718 return r.translated(0,d->yoff);
1721 qreal QQuickTextEditPrivate::getImplicitWidth() const
1723 Q_Q(const QQuickTextEdit);
1724 if (!requireImplicitWidth) {
1725 // We don't calculate implicitWidth unless it is required.
1726 // We need to force a size update now to ensure implicitWidth is calculated
1727 const_cast<QQuickTextEditPrivate*>(this)->requireImplicitWidth = true;
1728 const_cast<QQuickTextEdit*>(q)->updateSize();
1730 return implicitWidth;
1733 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1734 // need to do all the calculations each time
1735 void QQuickTextEdit::updateSize()
1737 Q_D(QQuickTextEdit);
1738 if (isComponentComplete()) {
1739 qreal naturalWidth = d->implicitWidth;
1740 // ### assumes that if the width is set, the text will fill to edges
1741 // ### (unless wrap is false, then clipping will occur)
1743 if (!d->requireImplicitWidth) {
1744 emit implicitWidthChanged();
1745 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1746 if (d->requireImplicitWidth)
1749 if (d->requireImplicitWidth) {
1750 d->document->setTextWidth(-1);
1751 naturalWidth = d->document->idealWidth();
1753 if (d->document->textWidth() != width())
1754 d->document->setTextWidth(width());
1756 d->document->setTextWidth(-1);
1758 QFontMetrics fm = QFontMetrics(d->font);
1760 dy -= (int)d->document->size().height();
1763 if (heightValid()) {
1764 if (d->vAlign == AlignBottom)
1766 else if (d->vAlign == AlignVCenter)
1773 if (nyoff != d->yoff)
1775 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1777 //### need to comfirm cost of always setting these
1778 int newWidth = qCeil(d->document->idealWidth());
1779 if (!widthValid() && d->document->textWidth() != newWidth)
1780 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1781 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1783 setImplicitWidth(newWidth);
1784 else if (d->requireImplicitWidth)
1785 setImplicitWidth(naturalWidth);
1786 qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
1787 setImplicitHeight(newHeight);
1789 d->paintedSize = QSize(newWidth, newHeight);
1790 emit paintedSizeChanged();
1797 void QQuickTextEdit::updateDocument()
1799 Q_D(QQuickTextEdit);
1800 d->documentDirty = true;
1802 if (isComponentComplete()) {
1808 void QQuickTextEdit::updateCursor()
1810 Q_D(QQuickTextEdit);
1811 if (isComponentComplete()) {
1812 updateImageCache(d->control->cursorRect());
1817 void QQuickTextEdit::updateTotalLines()
1819 Q_D(QQuickTextEdit);
1823 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1824 QTextLayout *layout = it.layout();
1827 subLines += layout->lineCount()-1;
1830 int newTotalLines = d->document->lineCount() + subLines;
1831 if (d->lineCount != newTotalLines) {
1832 d->lineCount = newTotalLines;
1833 emit lineCountChanged();
1837 void QQuickTextEditPrivate::updateDefaultTextOption()
1839 Q_Q(QQuickTextEdit);
1840 QTextOption opt = document->defaultTextOption();
1841 int oldAlignment = opt.alignment();
1843 QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
1844 if (rightToLeftText) {
1845 if (horizontalAlignment == QQuickTextEdit::AlignLeft)
1846 horizontalAlignment = QQuickTextEdit::AlignRight;
1847 else if (horizontalAlignment == QQuickTextEdit::AlignRight)
1848 horizontalAlignment = QQuickTextEdit::AlignLeft;
1850 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
1852 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1853 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
1855 bool oldUseDesignMetrics = opt.useDesignMetrics();
1856 bool useDesignMetrics = !qmlDisableDistanceField();
1857 opt.setUseDesignMetrics(useDesignMetrics);
1859 if (oldWrapMode == opt.wrapMode()
1860 && oldAlignment == opt.alignment()
1861 && oldUseDesignMetrics == useDesignMetrics) {
1864 document->setDefaultTextOption(opt);
1870 \qmlmethod void QtQuick2::TextEdit::openSoftwareInputPanel()
1872 Opens software input panels like virtual keyboards for typing, useful for
1873 customizing when you want the input keyboard to be shown and hidden in
1876 By default the opening of input panels follows the platform style. 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 QQuickTextEdit::openSoftwareInputPanel()
1909 qGuiApp->inputPanel()->show();
1913 \qmlmethod void QtQuick2::TextEdit::closeSoftwareInputPanel()
1915 Closes a software input panel like a virtual keyboard shown on the screen, useful
1916 for customizing when you want the input keyboard to be shown and hidden in
1919 By default the opening of input panels follows the platform style. Input panels are
1920 always closed if no editor has active focus.
1922 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1923 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1924 the behavior you want.
1926 Only relevant on platforms, which provide virtual keyboards.
1932 text: "Hello world!"
1933 activeFocusOnPress: false
1935 anchors.fill: parent
1937 if (!textEdit.activeFocus) {
1938 textEdit.forceActiveFocus();
1939 textEdit.openSoftwareInputPanel();
1941 textEdit.focus = false;
1944 onPressAndHold: textEdit.closeSoftwareInputPanel();
1949 void QQuickTextEdit::closeSoftwareInputPanel()
1952 qGuiApp->inputPanel()->hide();
1955 void QQuickTextEdit::focusInEvent(QFocusEvent *event)
1957 Q_D(const QQuickTextEdit);
1958 if (d->focusOnPress && !isReadOnly())
1959 openSoftwareInputPanel();
1960 QQuickImplicitSizeItem::focusInEvent(event);
1963 void QQuickTextEdit::q_canPasteChanged()
1965 Q_D(QQuickTextEdit);
1966 bool old = d->canPaste;
1967 d->canPaste = d->control->canPaste();
1968 if (old!=d->canPaste)
1969 emit canPasteChanged();