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 "private/qdeclarativetextedit_p.h"
43 #include "private/qdeclarativetextedit_p_p.h"
45 #include "private/qdeclarativeevents_p_p.h"
46 #include <private/qdeclarativeglobal_p.h>
47 #include <qdeclarativeinfo.h>
49 #include <QtCore/qmath.h>
51 #include <private/qtextengine_p.h>
52 #include <QTextLayout>
54 #include <QTextDocument>
55 #include <QTextObject>
56 #include <QGraphicsSceneMouseEvent>
60 #include <private/qtextcontrol_p.h>
65 \qmlclass TextEdit QDeclarativeTextEdit
66 \ingroup qml-basic-visual-elements
68 \brief The TextEdit item displays multiple lines of editable formatted text.
71 The TextEdit item displays a block of editable, formatted text.
73 It can display both plain and rich text. For example:
78 text: "<b>Hello</b> <i>World!</i>"
79 font.family: "Helvetica"
86 \image declarative-textedit.gif
88 Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
90 Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
91 to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
93 \snippet snippets/declarative/texteditor.qml 0
95 A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible
96 scrollbar, or a scrollbar that fades in to show location, etc.
98 Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
99 be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
100 from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
102 You can translate between cursor positions (characters from the start of the document) and pixel
103 points using positionAt() and positionToRectangle().
105 \sa Text, TextInput, {declarative/text/textselection}{Text Selection example}
109 \qmlsignal TextEdit::onLinkActivated(string link)
112 This handler is called when the user clicks on a link embedded in the text.
113 The link must be in rich text or HTML format and the
114 \a link string provides access to the particular link.
116 QDeclarativeTextEdit::QDeclarativeTextEdit(QDeclarativeItem *parent)
117 : QDeclarativeImplicitSizePaintedItem(*(new QDeclarativeTextEditPrivate), parent)
119 Q_D(QDeclarativeTextEdit);
123 QString QDeclarativeTextEdit::text() const
125 Q_D(const QDeclarativeTextEdit);
127 #ifndef QT_NO_TEXTHTMLPARSER
129 return d->document->toHtml();
132 return d->document->toPlainText();
136 \qmlproperty string TextEdit::font.family
138 Sets the family name of the font.
140 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
141 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
142 If the family isn't available a family will be set using the font matching algorithm.
146 \qmlproperty bool TextEdit::font.bold
148 Sets whether the font weight is bold.
152 \qmlproperty enumeration TextEdit::font.weight
154 Sets the font's weight.
156 The weight can be one of:
159 \o Font.Normal - the default
166 TextEdit { text: "Hello"; font.weight: Font.DemiBold }
171 \qmlproperty bool TextEdit::font.italic
173 Sets whether the font has an italic style.
177 \qmlproperty bool TextEdit::font.underline
179 Sets whether the text is underlined.
183 \qmlproperty bool TextEdit::font.strikeout
185 Sets whether the font has a strikeout style.
189 \qmlproperty real TextEdit::font.pointSize
191 Sets the font size in points. The point size must be greater than zero.
195 \qmlproperty int TextEdit::font.pixelSize
197 Sets the font size in pixels.
199 Using this function makes the font device dependent. Use
200 \l{TextEdit::font.pointSize} to set the size of the font in a
201 device independent manner.
205 \qmlproperty real TextEdit::font.letterSpacing
207 Sets the letter spacing for the font.
209 Letter spacing changes the default spacing between individual letters in the font.
210 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
214 \qmlproperty real TextEdit::font.wordSpacing
216 Sets the word spacing for the font.
218 Word spacing changes the default spacing between individual words.
219 A positive value increases the word spacing by a corresponding amount of pixels,
220 while a negative value decreases the inter-word spacing accordingly.
224 \qmlproperty enumeration TextEdit::font.capitalization
226 Sets the capitalization for the text.
229 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
230 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
231 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
232 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
233 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
237 TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
242 \qmlproperty string TextEdit::text
244 The text to display. If the text format is AutoText the text edit will
245 automatically determine whether the text should be treated as
246 rich text. This determination is made using Qt::mightBeRichText().
248 void QDeclarativeTextEdit::setText(const QString &text)
250 Q_D(QDeclarativeTextEdit);
251 if (QDeclarativeTextEdit::text() == text)
254 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
256 #ifndef QT_NO_TEXTHTMLPARSER
257 d->control->setHtml(text);
259 d->control->setPlainText(text);
262 d->control->setPlainText(text);
268 \qmlproperty enumeration TextEdit::textFormat
270 The way the text property should be displayed.
274 \o TextEdit.PlainText
278 The default is TextEdit.AutoText. If the text format is TextEdit.AutoText the text edit
279 will automatically determine whether the text should be treated as
280 rich text. This determination is made using Qt::mightBeRichText().
289 text: "<b>Hello</b> <i>World!</i>"
293 textFormat: TextEdit.RichText
294 text: "<b>Hello</b> <i>World!</i>"
298 textFormat: TextEdit.PlainText
299 text: "<b>Hello</b> <i>World!</i>"
303 \o \image declarative-textformat.png
306 QDeclarativeTextEdit::TextFormat QDeclarativeTextEdit::textFormat() const
308 Q_D(const QDeclarativeTextEdit);
312 void QDeclarativeTextEdit::setTextFormat(TextFormat format)
314 Q_D(QDeclarativeTextEdit);
315 if (format == d->format)
317 bool wasRich = d->richText;
318 d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
320 if (wasRich && !d->richText) {
321 d->control->setPlainText(d->text);
323 } else if (!wasRich && d->richText) {
324 #ifndef QT_NO_TEXTHTMLPARSER
325 d->control->setHtml(d->text);
327 d->control->setPlainText(d->text);
332 d->control->setAcceptRichText(d->format != PlainText);
333 emit textFormatChanged(d->format);
336 QFont QDeclarativeTextEdit::font() const
338 Q_D(const QDeclarativeTextEdit);
339 return d->sourceFont;
342 void QDeclarativeTextEdit::setFont(const QFont &font)
344 Q_D(QDeclarativeTextEdit);
345 if (d->sourceFont == font)
348 d->sourceFont = font;
349 QFont oldFont = d->font;
351 if (d->font.pointSizeF() != -1) {
353 qreal size = qRound(d->font.pointSizeF()*2.0);
354 d->font.setPointSizeF(size/2.0);
357 if (oldFont != d->font) {
359 d->document->setDefaultFont(d->font);
361 d->cursor->setHeight(QFontMetrics(d->font).height());
362 moveCursorDelegate();
367 emit fontChanged(d->sourceFont);
371 \qmlproperty color TextEdit::color
376 // green text using hexadecimal notation
377 TextEdit { color: "#00FF00" }
381 // steelblue text using SVG color name
382 TextEdit { color: "steelblue" }
385 QColor QDeclarativeTextEdit::color() const
387 Q_D(const QDeclarativeTextEdit);
391 void QDeclarativeTextEdit::setColor(const QColor &color)
393 Q_D(QDeclarativeTextEdit);
394 if (d->color == color)
399 QPalette pal = d->control->palette();
400 pal.setColor(QPalette::Text, color);
401 d->control->setPalette(pal);
403 emit colorChanged(d->color);
407 \qmlproperty color TextEdit::selectionColor
409 The text highlight color, used behind selections.
411 QColor QDeclarativeTextEdit::selectionColor() const
413 Q_D(const QDeclarativeTextEdit);
414 return d->selectionColor;
417 void QDeclarativeTextEdit::setSelectionColor(const QColor &color)
419 Q_D(QDeclarativeTextEdit);
420 if (d->selectionColor == color)
424 d->selectionColor = color;
425 QPalette pal = d->control->palette();
426 pal.setColor(QPalette::Highlight, color);
427 d->control->setPalette(pal);
429 emit selectionColorChanged(d->selectionColor);
433 \qmlproperty color TextEdit::selectedTextColor
435 The selected text color, used in selections.
437 QColor QDeclarativeTextEdit::selectedTextColor() const
439 Q_D(const QDeclarativeTextEdit);
440 return d->selectedTextColor;
443 void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color)
445 Q_D(QDeclarativeTextEdit);
446 if (d->selectedTextColor == color)
450 d->selectedTextColor = color;
451 QPalette pal = d->control->palette();
452 pal.setColor(QPalette::HighlightedText, color);
453 d->control->setPalette(pal);
455 emit selectedTextColorChanged(d->selectedTextColor);
459 \qmlproperty enumeration TextEdit::horizontalAlignment
460 \qmlproperty enumeration TextEdit::verticalAlignment
461 \qmlproperty enumeration TextEdit::effectiveHorizontalAlignment
463 Sets the horizontal and vertical alignment of the text within the TextEdit item's
464 width and height. By default, the text alignment follows the natural alignment
465 of the text, for example text that is read from left to right will be aligned to
468 Valid values for \c horizontalAlignment are:
470 \o TextEdit.AlignLeft (default)
471 \o TextEdit.AlignRight
472 \o TextEdit.AlignHCenter
473 \o TextEdit.AlignJustify
476 Valid values for \c verticalAlignment are:
478 \o TextEdit.AlignTop (default)
479 \o TextEdit.AlignBottom
480 \o TextEdit.AlignVCenter
483 When using the attached property LayoutMirroring::enabled to mirror application
484 layouts, the horizontal alignment of text will also be mirrored. However, the property
485 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
486 of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
488 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const
490 Q_D(const QDeclarativeTextEdit);
494 void QDeclarativeTextEdit::setHAlign(HAlignment align)
496 Q_D(QDeclarativeTextEdit);
497 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
498 d->hAlignImplicit = false;
499 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
500 d->updateDefaultTextOption();
505 void QDeclarativeTextEdit::resetHAlign()
507 Q_D(QDeclarativeTextEdit);
508 d->hAlignImplicit = true;
509 if (d->determineHorizontalAlignment() && isComponentComplete()) {
510 d->updateDefaultTextOption();
515 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::effectiveHAlign() const
517 Q_D(const QDeclarativeTextEdit);
518 QDeclarativeTextEdit::HAlignment effectiveAlignment = d->hAlign;
519 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
521 case QDeclarativeTextEdit::AlignLeft:
522 effectiveAlignment = QDeclarativeTextEdit::AlignRight;
524 case QDeclarativeTextEdit::AlignRight:
525 effectiveAlignment = QDeclarativeTextEdit::AlignLeft;
531 return effectiveAlignment;
534 bool QDeclarativeTextEditPrivate::setHAlign(QDeclarativeTextEdit::HAlignment alignment, bool forceAlign)
536 Q_Q(QDeclarativeTextEdit);
537 if (hAlign != alignment || forceAlign) {
538 QDeclarativeTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
540 emit q->horizontalAlignmentChanged(alignment);
541 if (oldEffectiveHAlign != q->effectiveHAlign())
542 emit q->effectiveHorizontalAlignmentChanged();
548 bool QDeclarativeTextEditPrivate::determineHorizontalAlignment()
550 Q_Q(QDeclarativeTextEdit);
551 if (hAlignImplicit && q->isComponentComplete()) {
552 bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
553 return setHAlign(alignToRight ? QDeclarativeTextEdit::AlignRight : QDeclarativeTextEdit::AlignLeft);
558 void QDeclarativeTextEditPrivate::mirrorChange()
560 Q_Q(QDeclarativeTextEdit);
561 if (q->isComponentComplete()) {
562 if (!hAlignImplicit && (hAlign == QDeclarativeTextEdit::AlignRight || hAlign == QDeclarativeTextEdit::AlignLeft)) {
563 updateDefaultTextOption();
565 emit q->effectiveHorizontalAlignmentChanged();
570 QDeclarativeTextEdit::VAlignment QDeclarativeTextEdit::vAlign() const
572 Q_D(const QDeclarativeTextEdit);
576 void QDeclarativeTextEdit::setVAlign(QDeclarativeTextEdit::VAlignment alignment)
578 Q_D(QDeclarativeTextEdit);
579 if (alignment == d->vAlign)
581 d->vAlign = alignment;
582 d->updateDefaultTextOption();
584 moveCursorDelegate();
585 emit verticalAlignmentChanged(d->vAlign);
589 \qmlproperty enumeration 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 QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const
605 Q_D(const QDeclarativeTextEdit);
609 void QDeclarativeTextEdit::setWrapMode(WrapMode mode)
611 Q_D(QDeclarativeTextEdit);
612 if (mode == d->wrapMode)
615 d->updateDefaultTextOption();
617 emit wrapModeChanged();
621 \qmlproperty int TextEdit::lineCount
624 Returns the total number of lines in the textEdit item.
626 int QDeclarativeTextEdit::lineCount() const
628 Q_D(const QDeclarativeTextEdit);
633 \qmlproperty real 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 QDeclarativeTextEdit::paintedWidth() const
640 Q_D(const QDeclarativeTextEdit);
641 return d->paintedSize.width();
645 \qmlproperty real 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 QDeclarativeTextEdit::paintedHeight() const
652 Q_D(const QDeclarativeTextEdit);
653 return d->paintedSize.height();
657 \qmlmethod rectangle 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 QDeclarativeTextEdit::positionToRectangle(int pos) const
665 Q_D(const QDeclarativeTextEdit);
666 QTextCursor c(d->document);
668 return d->control->cursorRect(c);
673 \qmlmethod int 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 QDeclarativeTextEdit::positionAt(int x, int y) const
682 Q_D(const QDeclarativeTextEdit);
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
703 void QDeclarativeTextEdit::moveCursorSelection(int pos)
705 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
706 Q_D(QDeclarativeTextEdit);
707 QTextCursor cursor = d->control->textCursor();
708 if (cursor.position() == pos)
710 cursor.setPosition(pos, QTextCursor::KeepAnchor);
711 d->control->setTextCursor(cursor);
715 \qmlmethod void TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
718 Moves the cursor to \a position and updates the selection according to the optional \a mode
719 parameter. (To only move the cursor, set the \l cursorPosition property.)
721 When this method is called it additionally sets either the
722 selectionStart or the selectionEnd (whichever was at the previous cursor position)
723 to the specified position. This allows you to easily extend and contract the selected
726 The selection mode specifies whether the selection is updated on a per character or a per word
727 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
730 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
731 the previous cursor position) to the specified position.
732 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
733 words between the specified postion and the previous cursor position. Words partially in the
737 For example, take this sequence of calls:
741 moveCursorSelection(9, TextEdit.SelectCharacters)
742 moveCursorSelection(7, TextEdit.SelectCharacters)
745 This moves the cursor to position 5, extend the selection end from 5 to 9
746 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
747 selected (the 6th and 7th characters).
749 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
750 before or on position 5 and extend the selection end to a word boundary on or past position 9.
752 void QDeclarativeTextEdit::moveCursorSelection(int pos, SelectionMode mode)
754 Q_D(QDeclarativeTextEdit);
755 QTextCursor cursor = d->control->textCursor();
756 if (cursor.position() == pos)
758 if (mode == SelectCharacters) {
759 cursor.setPosition(pos, QTextCursor::KeepAnchor);
760 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
761 if (cursor.anchor() > cursor.position()) {
762 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
763 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
764 if (cursor.position() == cursor.anchor())
765 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
767 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
769 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
770 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
773 cursor.setPosition(pos, QTextCursor::KeepAnchor);
774 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
775 if (cursor.position() != pos)
776 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
777 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
778 if (cursor.anchor() < cursor.position()) {
779 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
780 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
782 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
783 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
784 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
785 if (cursor.position() != cursor.anchor()) {
786 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
787 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
791 cursor.setPosition(pos, QTextCursor::KeepAnchor);
792 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
793 if (cursor.position() != pos) {
794 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
795 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
798 d->control->setTextCursor(cursor);
802 \qmlproperty bool TextEdit::cursorVisible
803 If true the text edit shows a cursor.
805 This property is set and unset when the text edit gets active focus, but it can also
806 be set directly (useful, for example, if a KeyProxy might forward keys to it).
808 bool QDeclarativeTextEdit::isCursorVisible() const
810 Q_D(const QDeclarativeTextEdit);
811 return d->cursorVisible;
814 void QDeclarativeTextEdit::setCursorVisible(bool on)
816 Q_D(QDeclarativeTextEdit);
817 if (d->cursorVisible == on)
819 d->cursorVisible = on;
820 QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
821 if (!on && !d->persistentSelection)
822 d->control->setCursorIsFocusIndicator(true);
823 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
824 emit cursorVisibleChanged(d->cursorVisible);
828 \qmlproperty int TextEdit::cursorPosition
829 The position of the cursor in the TextEdit.
831 int QDeclarativeTextEdit::cursorPosition() const
833 Q_D(const QDeclarativeTextEdit);
834 return d->control->textCursor().position();
837 void QDeclarativeTextEdit::setCursorPosition(int pos)
839 Q_D(QDeclarativeTextEdit);
840 if (pos < 0 || pos > d->text.length())
842 QTextCursor cursor = d->control->textCursor();
843 if (cursor.position() == pos && cursor.anchor() == pos)
845 cursor.setPosition(pos);
846 d->control->setTextCursor(cursor);
850 \qmlproperty Component TextEdit::cursorDelegate
851 The delegate for the cursor in the TextEdit.
853 If you set a cursorDelegate for a TextEdit, this delegate will be used for
854 drawing the cursor instead of the standard cursor. An instance of the
855 delegate will be created and managed by the text edit when a cursor is
856 needed, and the x and y properties of delegate instance will be set so as
857 to be one pixel before the top left of the current character.
859 Note that the root item of the delegate component must be a QDeclarativeItem or
860 QDeclarativeItem derived item.
862 QDeclarativeComponent* QDeclarativeTextEdit::cursorDelegate() const
864 Q_D(const QDeclarativeTextEdit);
865 return d->cursorComponent;
868 void QDeclarativeTextEdit::setCursorDelegate(QDeclarativeComponent* c)
870 Q_D(QDeclarativeTextEdit);
871 if(d->cursorComponent){
873 d->control->setCursorWidth(-1);
874 dirtyCache(cursorRectangle());
879 d->cursorComponent = c;
880 if(c && c->isReady()){
881 loadCursorDelegate();
884 connect(c, SIGNAL(statusChanged()),
885 this, SLOT(loadCursorDelegate()));
888 emit cursorDelegateChanged();
891 void QDeclarativeTextEdit::loadCursorDelegate()
893 Q_D(QDeclarativeTextEdit);
894 if(d->cursorComponent->isLoading())
896 d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this)));
898 d->control->setCursorWidth(0);
899 dirtyCache(cursorRectangle());
900 QDeclarative_setParent_noEvent(d->cursor, this);
901 d->cursor->setParentItem(this);
902 d->cursor->setHeight(QFontMetrics(d->font).height());
903 moveCursorDelegate();
905 qmlInfo(this) << "Error loading cursor delegate.";
910 \qmlproperty int TextEdit::selectionStart
912 The cursor position before the first character in the current selection.
914 This property is read-only. To change the selection, use select(start,end),
915 selectAll(), or selectWord().
917 \sa selectionEnd, cursorPosition, selectedText
919 int QDeclarativeTextEdit::selectionStart() const
921 Q_D(const QDeclarativeTextEdit);
922 return d->control->textCursor().selectionStart();
926 \qmlproperty int TextEdit::selectionEnd
928 The cursor position after the last character in the current selection.
930 This property is read-only. To change the selection, use select(start,end),
931 selectAll(), or selectWord().
933 \sa selectionStart, cursorPosition, selectedText
935 int QDeclarativeTextEdit::selectionEnd() const
937 Q_D(const QDeclarativeTextEdit);
938 return d->control->textCursor().selectionEnd();
942 \qmlproperty string TextEdit::selectedText
944 This read-only property provides the text currently selected in the
947 It is equivalent to the following snippet, but is faster and easier
950 //myTextEdit is the id of the TextEdit
951 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
952 myTextEdit.selectionEnd);
955 QString QDeclarativeTextEdit::selectedText() const
957 Q_D(const QDeclarativeTextEdit);
958 return d->control->textCursor().selectedText();
962 \qmlproperty bool TextEdit::activeFocusOnPress
964 Whether the TextEdit should gain active focus on a mouse press. By default this is
967 bool QDeclarativeTextEdit::focusOnPress() const
969 Q_D(const QDeclarativeTextEdit);
970 return d->focusOnPress;
973 void QDeclarativeTextEdit::setFocusOnPress(bool on)
975 Q_D(QDeclarativeTextEdit);
976 if (d->focusOnPress == on)
978 d->focusOnPress = on;
979 emit activeFocusOnPressChanged(d->focusOnPress);
983 \qmlproperty bool TextEdit::persistentSelection
985 Whether the TextEdit should keep the selection visible when it loses active focus to another
986 item in the scene. By default this is set to true;
988 bool QDeclarativeTextEdit::persistentSelection() const
990 Q_D(const QDeclarativeTextEdit);
991 return d->persistentSelection;
994 void QDeclarativeTextEdit::setPersistentSelection(bool on)
996 Q_D(QDeclarativeTextEdit);
997 if (d->persistentSelection == on)
999 d->persistentSelection = on;
1000 emit persistentSelectionChanged(d->persistentSelection);
1004 \qmlproperty real TextEdit::textMargin
1006 The margin, in pixels, around the text in the TextEdit.
1008 qreal QDeclarativeTextEdit::textMargin() const
1010 Q_D(const QDeclarativeTextEdit);
1011 return d->textMargin;
1014 void QDeclarativeTextEdit::setTextMargin(qreal margin)
1016 Q_D(QDeclarativeTextEdit);
1017 if (d->textMargin == margin)
1019 d->textMargin = margin;
1020 d->document->setDocumentMargin(d->textMargin);
1021 emit textMarginChanged(d->textMargin);
1024 void QDeclarativeTextEdit::geometryChanged(const QRectF &newGeometry,
1025 const QRectF &oldGeometry)
1027 if (newGeometry.width() != oldGeometry.width())
1029 QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
1033 Ensures any delayed caching or data loading the class
1034 needs to performed is complete.
1036 void QDeclarativeTextEdit::componentComplete()
1038 Q_D(QDeclarativeTextEdit);
1039 QDeclarativePaintedItem::componentComplete();
1041 d->determineHorizontalAlignment();
1042 d->updateDefaultTextOption();
1049 \qmlproperty bool TextEdit::selectByMouse
1053 If true, the user can use the mouse to select text in some
1054 platform-specific way. Note that for some platforms this may
1055 not be an appropriate interaction (eg. may conflict with how
1056 the text needs to behave inside a Flickable.
1058 bool QDeclarativeTextEdit::selectByMouse() const
1060 Q_D(const QDeclarativeTextEdit);
1061 return d->selectByMouse;
1064 void QDeclarativeTextEdit::setSelectByMouse(bool on)
1066 Q_D(QDeclarativeTextEdit);
1067 if (d->selectByMouse != on) {
1068 d->selectByMouse = on;
1069 setKeepMouseGrab(on);
1071 setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1073 setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1074 emit selectByMouseChanged(on);
1080 \qmlproperty enum TextEdit::mouseSelectionMode
1083 Specifies how text should be selected using a mouse.
1086 \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1087 \o TextEdit.SelectWords - The selection is updated with whole words.
1090 This property only applies when \l selectByMouse is true.
1093 QDeclarativeTextEdit::SelectionMode QDeclarativeTextEdit::mouseSelectionMode() const
1095 Q_D(const QDeclarativeTextEdit);
1096 return d->mouseSelectionMode;
1099 void QDeclarativeTextEdit::setMouseSelectionMode(SelectionMode mode)
1101 Q_D(QDeclarativeTextEdit);
1102 if (d->mouseSelectionMode != mode) {
1103 d->mouseSelectionMode = mode;
1104 d->control->setWordSelectionEnabled(mode == SelectWords);
1105 emit mouseSelectionModeChanged(mode);
1110 \qmlproperty bool TextEdit::readOnly
1112 Whether the user can interact with the TextEdit item. If this
1113 property is set to true the text cannot be edited by user interaction.
1115 By default this property is false.
1117 void QDeclarativeTextEdit::setReadOnly(bool r)
1119 Q_D(QDeclarativeTextEdit);
1120 if (r == isReadOnly())
1123 setFlag(QGraphicsItem::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 QDeclarativeTextEdit::isReadOnly() const
1139 Q_D(const QDeclarativeTextEdit);
1140 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1144 Sets how the text edit should interact with user input to the given
1147 void QDeclarativeTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1149 Q_D(QDeclarativeTextEdit);
1150 d->control->setTextInteractionFlags(flags);
1154 Returns the flags specifying how the text edit should interact
1157 Qt::TextInteractionFlags QDeclarativeTextEdit::textInteractionFlags() const
1159 Q_D(const QDeclarativeTextEdit);
1160 return d->control->textInteractionFlags();
1164 \qmlproperty rectangle TextEdit::cursorRectangle
1166 The rectangle where the text cursor is rendered
1167 within the text edit. Read-only.
1169 QRect QDeclarativeTextEdit::cursorRectangle() const
1171 Q_D(const QDeclarativeTextEdit);
1172 return d->control->cursorRect().toRect().translated(0,d->yoff);
1178 Handles the given \a event.
1180 bool QDeclarativeTextEdit::event(QEvent *event)
1182 Q_D(QDeclarativeTextEdit);
1183 if (event->type() == QEvent::ShortcutOverride) {
1184 d->control->processEvent(event, QPointF(0, -d->yoff));
1185 return event->isAccepted();
1187 return QDeclarativePaintedItem::event(event);
1192 Handles the given key \a event.
1194 void QDeclarativeTextEdit::keyPressEvent(QKeyEvent *event)
1196 Q_D(QDeclarativeTextEdit);
1197 keyPressPreHandler(event);
1198 if (!event->isAccepted())
1199 d->control->processEvent(event, QPointF(0, -d->yoff));
1200 if (!event->isAccepted())
1201 QDeclarativePaintedItem::keyPressEvent(event);
1206 Handles the given key \a event.
1208 void QDeclarativeTextEdit::keyReleaseEvent(QKeyEvent *event)
1210 Q_D(QDeclarativeTextEdit);
1211 keyReleasePreHandler(event);
1212 if (!event->isAccepted())
1213 d->control->processEvent(event, QPointF(0, -d->yoff));
1214 if (!event->isAccepted())
1215 QDeclarativePaintedItem::keyReleaseEvent(event);
1218 void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus)
1220 Q_Q(QDeclarativeTextEdit);
1221 q->setCursorVisible(hasFocus && scene && scene->hasFocus());
1222 QDeclarativeItemPrivate::focusChanged(hasFocus);
1226 \qmlmethod void TextEdit::deselect()
1229 Removes active text selection.
1231 void QDeclarativeTextEdit::deselect()
1233 Q_D(QDeclarativeTextEdit);
1234 QTextCursor c = d->control->textCursor();
1236 d->control->setTextCursor(c);
1240 \qmlmethod void TextEdit::selectAll()
1242 Causes all text to be selected.
1244 void QDeclarativeTextEdit::selectAll()
1246 Q_D(QDeclarativeTextEdit);
1247 d->control->selectAll();
1251 \qmlmethod void TextEdit::selectWord()
1253 Causes the word closest to the current cursor position to be selected.
1255 void QDeclarativeTextEdit::selectWord()
1257 Q_D(QDeclarativeTextEdit);
1258 QTextCursor c = d->control->textCursor();
1259 c.select(QTextCursor::WordUnderCursor);
1260 d->control->setTextCursor(c);
1264 \qmlmethod void TextEdit::select(int start, int end)
1266 Causes the text from \a start to \a end to be selected.
1268 If either start or end is out of range, the selection is not changed.
1270 After calling this, selectionStart will become the lesser
1271 and selectionEnd will become the greater (regardless of the order passed
1274 \sa selectionStart, selectionEnd
1276 void QDeclarativeTextEdit::select(int start, int end)
1278 Q_D(QDeclarativeTextEdit);
1279 if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
1281 QTextCursor cursor = d->control->textCursor();
1282 cursor.beginEditBlock();
1283 cursor.setPosition(start, QTextCursor::MoveAnchor);
1284 cursor.setPosition(end, QTextCursor::KeepAnchor);
1285 cursor.endEditBlock();
1286 d->control->setTextCursor(cursor);
1289 updateSelectionMarkers();
1293 \qmlmethod void TextEdit::isRightToLeft(int start, int end)
1295 Returns true if the natural reading direction of the editor text
1296 found between positions \a start and \a end is right to left.
1298 bool QDeclarativeTextEdit::isRightToLeft(int start, int end)
1300 Q_D(QDeclarativeTextEdit);
1302 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1305 return d->text.mid(start, end - start).isRightToLeft();
1309 #ifndef QT_NO_CLIPBOARD
1311 \qmlmethod TextEdit::cut()
1313 Moves the currently selected text to the system clipboard.
1315 void QDeclarativeTextEdit::cut()
1317 Q_D(QDeclarativeTextEdit);
1322 \qmlmethod TextEdit::copy()
1324 Copies the currently selected text to the system clipboard.
1326 void QDeclarativeTextEdit::copy()
1328 Q_D(QDeclarativeTextEdit);
1333 \qmlmethod TextEdit::paste()
1335 Replaces the currently selected text by the contents of the system clipboard.
1337 void QDeclarativeTextEdit::paste()
1339 Q_D(QDeclarativeTextEdit);
1340 d->control->paste();
1342 #endif // QT_NO_CLIPBOARD
1346 Handles the given mouse \a event.
1348 void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
1350 Q_D(QDeclarativeTextEdit);
1351 if (d->focusOnPress){
1352 bool hadActiveFocus = hasActiveFocus();
1354 if (d->showInputPanelOnFocus) {
1355 if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1356 // re-open input panel on press if already focused
1357 openSoftwareInputPanel();
1359 } else { // show input panel on click
1360 if (hasActiveFocus() && !hadActiveFocus) {
1361 d->clickCausedFocus = true;
1366 d->control->processEvent(event, QPointF(0, -d->yoff));
1367 if (!event->isAccepted())
1368 QDeclarativePaintedItem::mousePressEvent(event);
1373 Handles the given mouse \a event.
1375 void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1377 Q_D(QDeclarativeTextEdit);
1378 d->control->processEvent(event, QPointF(0, -d->yoff));
1379 if (!d->showInputPanelOnFocus) { // input panel on click
1380 if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1381 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1382 if (view->scene() && view->scene() == scene()) {
1383 qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1388 d->clickCausedFocus = false;
1390 if (!event->isAccepted())
1391 QDeclarativePaintedItem::mouseReleaseEvent(event);
1396 Handles the given mouse \a event.
1398 void QDeclarativeTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1400 Q_D(QDeclarativeTextEdit);
1402 d->control->processEvent(event, QPointF(0, -d->yoff));
1403 if (!event->isAccepted())
1404 QDeclarativePaintedItem::mouseDoubleClickEvent(event);
1410 Handles the given mouse \a event.
1412 void QDeclarativeTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1414 Q_D(QDeclarativeTextEdit);
1415 d->control->processEvent(event, QPointF(0, -d->yoff));
1416 if (!event->isAccepted())
1417 QDeclarativePaintedItem::mouseMoveEvent(event);
1422 Handles the given input method \a event.
1424 void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event)
1426 Q_D(QDeclarativeTextEdit);
1427 const bool wasComposing = isInputMethodComposing();
1428 d->control->processEvent(event, QPointF(0, -d->yoff));
1429 if (wasComposing != isInputMethodComposing())
1430 emit inputMethodComposingChanged();
1435 Returns the value of the given \a property.
1437 QVariant QDeclarativeTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1439 Q_D(const QDeclarativeTextEdit);
1440 return d->control->inputMethodQuery(property);
1444 Draws the contents of the text edit using the given \a painter within
1445 the given \a bounds.
1447 void QDeclarativeTextEdit::drawContents(QPainter *painter, const QRect &bounds)
1449 Q_D(QDeclarativeTextEdit);
1451 painter->setRenderHint(QPainter::TextAntialiasing, true);
1452 painter->translate(0,d->yoff);
1454 d->control->drawContents(painter, bounds.translated(0,-d->yoff));
1456 painter->translate(0,-d->yoff);
1459 void QDeclarativeTextEdit::updateImgCache(const QRectF &rf)
1461 Q_D(const QDeclarativeTextEdit);
1463 if (!rf.isValid()) {
1464 r = QRect(0,0,INT_MAX,INT_MAX);
1467 if (r.height() > INT_MAX/2) {
1468 // Take care of overflow when translating "everything"
1469 r.setTop(r.y() + d->yoff);
1470 r.setBottom(INT_MAX/2);
1472 r = r.translated(0,d->yoff);
1480 \qmlproperty bool TextEdit::smooth
1482 This property holds whether the text is smoothly scaled or transformed.
1484 Smooth filtering gives better visual quality, but is slower. If
1485 the item is displayed at its natural size, this property has no visual or
1488 \note Generally scaling artifacts are only visible if the item is stationary on
1489 the screen. A common pattern when animating an item is to disable smooth
1490 filtering at the beginning of the animation and reenable it at the conclusion.
1494 \qmlproperty bool TextEdit::canPaste
1497 Returns true if the TextEdit is writable and the content of the clipboard is
1498 suitable for pasting into the TextEdit.
1500 bool QDeclarativeTextEdit::canPaste() const
1502 Q_D(const QDeclarativeTextEdit);
1507 \qmlproperty bool TextEdit::inputMethodComposing
1511 This property holds whether the TextEdit has partial text input from an
1514 While it is composing an input method may rely on mouse or key events from
1515 the TextEdit to edit or commit the partial text. This property can be used
1516 to determine when to disable events handlers that may interfere with the
1517 correct operation of an input method.
1519 bool QDeclarativeTextEdit::isInputMethodComposing() const
1521 Q_D(const QDeclarativeTextEdit);
1522 if (QTextLayout *layout = d->control->textCursor().block().layout())
1523 return layout->preeditAreaText().length() > 0;
1527 void QDeclarativeTextEditPrivate::init()
1529 Q_Q(QDeclarativeTextEdit);
1531 q->setSmooth(smooth);
1532 q->setAcceptedMouseButtons(Qt::LeftButton);
1533 q->setFlag(QGraphicsItem::ItemHasNoContents, false);
1534 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
1536 control = new QTextControl(q);
1537 control->setIgnoreUnusedNavigationEvents(true);
1538 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1539 control->setDragEnabled(false);
1541 // QTextControl follows the default text color
1542 // defined by the platform, declarative text
1543 // should be black by default
1544 QPalette pal = control->palette();
1545 if (pal.color(QPalette::Text) != color) {
1546 pal.setColor(QPalette::Text, color);
1547 control->setPalette(pal);
1550 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF)));
1552 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1553 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1554 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1555 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1556 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1557 QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate()));
1558 QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1559 #ifndef QT_NO_CLIPBOARD
1560 QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged()));
1561 QObject::connect(QApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1562 canPaste = control->canPaste();
1565 document = control->document();
1566 document->setDefaultFont(font);
1567 document->setDocumentMargin(textMargin);
1568 document->setUndoRedoEnabled(false); // flush undo buffer.
1569 document->setUndoRedoEnabled(true);
1570 updateDefaultTextOption();
1573 void QDeclarativeTextEdit::q_textChanged()
1575 Q_D(QDeclarativeTextEdit);
1577 d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
1578 d->determineHorizontalAlignment();
1579 d->updateDefaultTextOption();
1582 emit textChanged(d->text);
1585 void QDeclarativeTextEdit::moveCursorDelegate()
1587 Q_D(QDeclarativeTextEdit);
1589 emit cursorRectangleChanged();
1592 QRectF cursorRect = cursorRectangle();
1593 d->cursor->setX(cursorRect.x());
1594 d->cursor->setY(cursorRect.y());
1597 void QDeclarativeTextEditPrivate::updateSelection()
1599 Q_Q(QDeclarativeTextEdit);
1600 QTextCursor cursor = control->textCursor();
1601 bool startChange = (lastSelectionStart != cursor.selectionStart());
1602 bool endChange = (lastSelectionEnd != cursor.selectionEnd());
1603 cursor.beginEditBlock();
1604 cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
1605 cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
1606 cursor.endEditBlock();
1607 control->setTextCursor(cursor);
1609 q->selectionStartChanged();
1611 q->selectionEndChanged();
1614 void QDeclarativeTextEdit::updateSelectionMarkers()
1616 Q_D(QDeclarativeTextEdit);
1617 if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
1618 d->lastSelectionStart = d->control->textCursor().selectionStart();
1619 emit selectionStartChanged();
1621 if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
1622 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1623 emit selectionEndChanged();
1627 QRectF QDeclarativeTextEdit::boundingRect() const
1629 Q_D(const QDeclarativeTextEdit);
1630 QRectF r = QDeclarativePaintedItem::boundingRect();
1631 int cursorWidth = 1;
1633 cursorWidth = d->cursor->width();
1634 if(!d->document->isEmpty())
1635 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1637 // Could include font max left/right bearings to either side of rectangle.
1639 r.setRight(r.right() + cursorWidth);
1640 return r.translated(0,d->yoff);
1643 qreal QDeclarativeTextEditPrivate::implicitWidth() const
1645 Q_Q(const QDeclarativeTextEdit);
1646 if (!requireImplicitWidth) {
1647 // We don't calculate implicitWidth unless it is required.
1648 // We need to force a size update now to ensure implicitWidth is calculated
1649 const_cast<QDeclarativeTextEditPrivate*>(this)->requireImplicitWidth = true;
1650 const_cast<QDeclarativeTextEdit*>(q)->updateSize();
1652 return mImplicitWidth;
1655 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1656 // need to do all the calculations each time
1657 void QDeclarativeTextEdit::updateSize()
1659 Q_D(QDeclarativeTextEdit);
1660 if (isComponentComplete()) {
1661 qreal naturalWidth = d->mImplicitWidth;
1662 // ### assumes that if the width is set, the text will fill to edges
1663 // ### (unless wrap is false, then clipping will occur)
1665 if (!d->requireImplicitWidth) {
1666 emit implicitWidthChanged();
1667 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1668 if (d->requireImplicitWidth)
1671 if (d->requireImplicitWidth) {
1672 d->document->setTextWidth(-1);
1673 naturalWidth = d->document->idealWidth();
1675 if (d->document->textWidth() != width())
1676 d->document->setTextWidth(width());
1678 d->document->setTextWidth(-1);
1680 QFontMetrics fm = QFontMetrics(d->font);
1682 dy -= (int)d->document->size().height();
1685 if (heightValid()) {
1686 if (d->vAlign == AlignBottom)
1688 else if (d->vAlign == AlignVCenter)
1695 if (nyoff != d->yoff) {
1696 prepareGeometryChange();
1699 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1701 //### need to comfirm cost of always setting these
1702 int newWidth = qCeil(d->document->idealWidth());
1703 if (!widthValid() && d->document->textWidth() != newWidth)
1704 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1705 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1707 setImplicitWidth(newWidth);
1708 else if (d->requireImplicitWidth)
1709 setImplicitWidth(naturalWidth);
1710 qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
1711 setImplicitHeight(newHeight);
1713 d->paintedSize = QSize(newWidth, newHeight);
1714 setContentsSize(d->paintedSize);
1715 emit paintedSizeChanged();
1722 void QDeclarativeTextEdit::updateTotalLines()
1724 Q_D(QDeclarativeTextEdit);
1728 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1729 QTextLayout *layout = it.layout();
1732 subLines += layout->lineCount()-1;
1735 int newTotalLines = d->document->lineCount() + subLines;
1736 if (d->lineCount != newTotalLines) {
1737 d->lineCount = newTotalLines;
1738 emit lineCountChanged();
1742 void QDeclarativeTextEditPrivate::updateDefaultTextOption()
1744 Q_Q(QDeclarativeTextEdit);
1745 QTextOption opt = document->defaultTextOption();
1746 int oldAlignment = opt.alignment();
1748 QDeclarativeTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
1749 if (rightToLeftText) {
1750 if (horizontalAlignment == QDeclarativeTextEdit::AlignLeft)
1751 horizontalAlignment = QDeclarativeTextEdit::AlignRight;
1752 else if (horizontalAlignment == QDeclarativeTextEdit::AlignRight)
1753 horizontalAlignment = QDeclarativeTextEdit::AlignLeft;
1755 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
1757 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1758 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
1760 if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
1762 document->setDefaultTextOption(opt);
1767 \qmlmethod void TextEdit::openSoftwareInputPanel()
1769 Opens software input panels like virtual keyboards for typing, useful for
1770 customizing when you want the input keyboard to be shown and hidden in
1773 By default the opening of input panels follows the platform style. On Symbian^1 and
1774 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1775 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1776 always closed if no editor has active focus.
1778 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1779 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1780 the behavior you want.
1782 Only relevant on platforms, which provide virtual keyboards.
1788 text: "Hello world!"
1789 activeFocusOnPress: false
1791 anchors.fill: parent
1793 if (!textEdit.activeFocus) {
1794 textEdit.forceActiveFocus();
1795 textEdit.openSoftwareInputPanel();
1797 textEdit.focus = false;
1800 onPressAndHold: textEdit.closeSoftwareInputPanel();
1805 void QDeclarativeTextEdit::openSoftwareInputPanel()
1807 QEvent event(QEvent::RequestSoftwareInputPanel);
1809 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1810 if (view->scene() && view->scene() == scene()) {
1811 QApplication::sendEvent(view, &event);
1818 \qmlmethod void TextEdit::closeSoftwareInputPanel()
1820 Closes a software input panel like a virtual keyboard shown on the screen, useful
1821 for customizing when you want the input keyboard to be shown and hidden in
1824 By default the opening of input panels follows the platform style. On Symbian^1 and
1825 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1826 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1827 always closed if no editor has active focus.
1829 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1830 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1831 the behavior you want.
1833 Only relevant on platforms, which provide virtual keyboards.
1839 text: "Hello world!"
1840 activeFocusOnPress: false
1842 anchors.fill: parent
1844 if (!textEdit.activeFocus) {
1845 textEdit.forceActiveFocus();
1846 textEdit.openSoftwareInputPanel();
1848 textEdit.focus = false;
1851 onPressAndHold: textEdit.closeSoftwareInputPanel();
1856 void QDeclarativeTextEdit::closeSoftwareInputPanel()
1858 QEvent event(QEvent::CloseSoftwareInputPanel);
1860 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1861 if (view->scene() && view->scene() == scene()) {
1862 QApplication::sendEvent(view, &event);
1868 void QDeclarativeTextEdit::focusInEvent(QFocusEvent *event)
1870 Q_D(const QDeclarativeTextEdit);
1871 if (d->showInputPanelOnFocus) {
1872 if (d->focusOnPress && !isReadOnly()) {
1873 openSoftwareInputPanel();
1876 QDeclarativePaintedItem::focusInEvent(event);
1879 void QDeclarativeTextEdit::q_canPasteChanged()
1881 Q_D(QDeclarativeTextEdit);
1882 bool old = d->canPaste;
1883 d->canPaste = d->control->canPaste();
1884 if(old!=d->canPaste)
1885 emit canPasteChanged();