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
462 Sets the horizontal and vertical alignment of the text within the TextEdit item's
463 width and height. By default, the text alignment follows the natural alignment
464 of the text, for example text that is read from left to right will be aligned to
467 Valid values for \c horizontalAlignment are:
469 \o TextEdit.AlignLeft (default)
470 \o TextEdit.AlignRight
471 \o TextEdit.AlignHCenter
472 \o TextEdit.AlignJustify
475 Valid values for \c verticalAlignment are:
477 \o TextEdit.AlignTop (default)
478 \o TextEdit.AlignBottom
479 \o TextEdit.AlignVCenter
482 When using the attached property \l {LayoutMirroring::enabled} to mirror application
483 layouts, the horizontal alignment of text will also be mirrored. However, the property
484 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
485 of TextEdit, use the property \l {LayoutMirroring::enabled}.
487 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const
489 Q_D(const QDeclarativeTextEdit);
493 void QDeclarativeTextEdit::setHAlign(HAlignment align)
495 Q_D(QDeclarativeTextEdit);
496 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
497 d->hAlignImplicit = false;
498 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
499 d->updateDefaultTextOption();
504 void QDeclarativeTextEdit::resetHAlign()
506 Q_D(QDeclarativeTextEdit);
507 d->hAlignImplicit = true;
508 if (d->determineHorizontalAlignment() && isComponentComplete()) {
509 d->updateDefaultTextOption();
514 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::effectiveHAlign() const
516 Q_D(const QDeclarativeTextEdit);
517 QDeclarativeTextEdit::HAlignment effectiveAlignment = d->hAlign;
518 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
520 case QDeclarativeTextEdit::AlignLeft:
521 effectiveAlignment = QDeclarativeTextEdit::AlignRight;
523 case QDeclarativeTextEdit::AlignRight:
524 effectiveAlignment = QDeclarativeTextEdit::AlignLeft;
530 return effectiveAlignment;
533 bool QDeclarativeTextEditPrivate::setHAlign(QDeclarativeTextEdit::HAlignment alignment, bool forceAlign)
535 Q_Q(QDeclarativeTextEdit);
536 if (hAlign != alignment || forceAlign) {
537 QDeclarativeTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
539 emit q->horizontalAlignmentChanged(alignment);
545 bool QDeclarativeTextEditPrivate::determineHorizontalAlignment()
547 Q_Q(QDeclarativeTextEdit);
548 if (hAlignImplicit && q->isComponentComplete()) {
550 if (text.isEmpty()) {
551 const QString preeditText = control->textCursor().block().layout()->preeditAreaText();
552 alignToRight = preeditText.isEmpty()
553 ? QApplication::keyboardInputDirection() == Qt::RightToLeft
554 : preeditText.isRightToLeft();
556 alignToRight = rightToLeftText;
558 return setHAlign(alignToRight ? QDeclarativeTextEdit::AlignRight : QDeclarativeTextEdit::AlignLeft);
563 void QDeclarativeTextEditPrivate::mirrorChange()
565 Q_Q(QDeclarativeTextEdit);
566 if (q->isComponentComplete()) {
567 if (!hAlignImplicit && (hAlign == QDeclarativeTextEdit::AlignRight || hAlign == QDeclarativeTextEdit::AlignLeft)) {
568 updateDefaultTextOption();
574 QDeclarativeTextEdit::VAlignment QDeclarativeTextEdit::vAlign() const
576 Q_D(const QDeclarativeTextEdit);
580 void QDeclarativeTextEdit::setVAlign(QDeclarativeTextEdit::VAlignment alignment)
582 Q_D(QDeclarativeTextEdit);
583 if (alignment == d->vAlign)
585 d->vAlign = alignment;
586 d->updateDefaultTextOption();
588 moveCursorDelegate();
589 emit verticalAlignmentChanged(d->vAlign);
593 \qmlproperty enumeration TextEdit::wrapMode
595 Set this property to wrap the text to the TextEdit item's width.
596 The text will only wrap if an explicit width has been set.
599 \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
600 \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
601 \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
602 \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.
605 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
607 QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const
609 Q_D(const QDeclarativeTextEdit);
613 void QDeclarativeTextEdit::setWrapMode(WrapMode mode)
615 Q_D(QDeclarativeTextEdit);
616 if (mode == d->wrapMode)
619 d->updateDefaultTextOption();
621 emit wrapModeChanged();
625 \qmlproperty int TextEdit::lineCount
628 Returns the total number of lines in the textEdit item.
630 int QDeclarativeTextEdit::lineCount() const
632 Q_D(const QDeclarativeTextEdit);
637 \qmlproperty real TextEdit::paintedWidth
639 Returns the width of the text, including the width past the width
640 which is covered due to insufficient wrapping if \l wrapMode is set.
642 qreal QDeclarativeTextEdit::paintedWidth() const
644 Q_D(const QDeclarativeTextEdit);
645 return d->paintedSize.width();
649 \qmlproperty real TextEdit::paintedHeight
651 Returns the height of the text, including the height past the height
652 that is covered if the text does not fit within the set height.
654 qreal QDeclarativeTextEdit::paintedHeight() const
656 Q_D(const QDeclarativeTextEdit);
657 return d->paintedSize.height();
661 \qmlmethod rectangle TextEdit::positionToRectangle(position)
663 Returns the rectangle at the given \a position in the text. The x, y,
664 and height properties correspond to the cursor that would describe
667 QRectF QDeclarativeTextEdit::positionToRectangle(int pos) const
669 Q_D(const QDeclarativeTextEdit);
670 QTextCursor c(d->document);
672 return d->control->cursorRect(c);
677 \qmlmethod int TextEdit::positionAt(int x, int y)
679 Returns the text position closest to pixel position (\a x, \a y).
681 Position 0 is before the first character, position 1 is after the first character
682 but before the second, and so on until position \l {text}.length, which is after all characters.
684 int QDeclarativeTextEdit::positionAt(int x, int y) const
686 Q_D(const QDeclarativeTextEdit);
687 int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
688 QTextCursor cursor = d->control->textCursor();
689 if (r > cursor.position()) {
690 // The cursor position includes positions within the preedit text, but only positions in the
691 // same text block are offset so it is possible to get a position that is either part of the
692 // preedit or the next text block.
693 QTextLayout *layout = cursor.block().layout();
694 const int preeditLength = layout
695 ? layout->preeditAreaText().length()
697 if (preeditLength > 0
698 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
699 r = r > cursor.position() + preeditLength
707 void QDeclarativeTextEdit::moveCursorSelection(int pos)
709 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
710 Q_D(QDeclarativeTextEdit);
711 QTextCursor cursor = d->control->textCursor();
712 if (cursor.position() == pos)
714 cursor.setPosition(pos, QTextCursor::KeepAnchor);
715 d->control->setTextCursor(cursor);
719 \qmlmethod void TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
722 Moves the cursor to \a position and updates the selection according to the optional \a mode
723 parameter. (To only move the cursor, set the \l cursorPosition property.)
725 When this method is called it additionally sets either the
726 selectionStart or the selectionEnd (whichever was at the previous cursor position)
727 to the specified position. This allows you to easily extend and contract the selected
730 The selection mode specifies whether the selection is updated on a per character or a per word
731 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
734 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
735 the previous cursor position) to the specified position.
736 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
737 words between the specified postion and the previous cursor position. Words partially in the
741 For example, take this sequence of calls:
745 moveCursorSelection(9, TextEdit.SelectCharacters)
746 moveCursorSelection(7, TextEdit.SelectCharacters)
749 This moves the cursor to position 5, extend the selection end from 5 to 9
750 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
751 selected (the 6th and 7th characters).
753 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
754 before or on position 5 and extend the selection end to a word boundary on or past position 9.
756 void QDeclarativeTextEdit::moveCursorSelection(int pos, SelectionMode mode)
758 Q_D(QDeclarativeTextEdit);
759 QTextCursor cursor = d->control->textCursor();
760 if (cursor.position() == pos)
762 if (mode == SelectCharacters) {
763 cursor.setPosition(pos, QTextCursor::KeepAnchor);
764 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
765 if (cursor.anchor() > cursor.position()) {
766 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
767 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
768 if (cursor.position() == cursor.anchor())
769 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
771 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
773 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
774 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
777 cursor.setPosition(pos, QTextCursor::KeepAnchor);
778 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
779 if (cursor.position() != pos)
780 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
781 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
782 if (cursor.anchor() < cursor.position()) {
783 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
784 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
786 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
787 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
788 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
789 if (cursor.position() != cursor.anchor()) {
790 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
791 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
795 cursor.setPosition(pos, QTextCursor::KeepAnchor);
796 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
797 if (cursor.position() != pos) {
798 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
799 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
802 d->control->setTextCursor(cursor);
806 \qmlproperty bool TextEdit::cursorVisible
807 If true the text edit shows a cursor.
809 This property is set and unset when the text edit gets active focus, but it can also
810 be set directly (useful, for example, if a KeyProxy might forward keys to it).
812 bool QDeclarativeTextEdit::isCursorVisible() const
814 Q_D(const QDeclarativeTextEdit);
815 return d->cursorVisible;
818 void QDeclarativeTextEdit::setCursorVisible(bool on)
820 Q_D(QDeclarativeTextEdit);
821 if (d->cursorVisible == on)
823 d->cursorVisible = on;
824 QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
825 if (!on && !d->persistentSelection)
826 d->control->setCursorIsFocusIndicator(true);
827 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
828 emit cursorVisibleChanged(d->cursorVisible);
832 \qmlproperty int TextEdit::cursorPosition
833 The position of the cursor in the TextEdit.
835 int QDeclarativeTextEdit::cursorPosition() const
837 Q_D(const QDeclarativeTextEdit);
838 return d->control->textCursor().position();
841 void QDeclarativeTextEdit::setCursorPosition(int pos)
843 Q_D(QDeclarativeTextEdit);
844 if (pos < 0 || pos > d->text.length())
846 QTextCursor cursor = d->control->textCursor();
847 if (cursor.position() == pos && cursor.anchor() == pos)
849 cursor.setPosition(pos);
850 d->control->setTextCursor(cursor);
854 \qmlproperty Component TextEdit::cursorDelegate
855 The delegate for the cursor in the TextEdit.
857 If you set a cursorDelegate for a TextEdit, this delegate will be used for
858 drawing the cursor instead of the standard cursor. An instance of the
859 delegate will be created and managed by the text edit when a cursor is
860 needed, and the x and y properties of delegate instance will be set so as
861 to be one pixel before the top left of the current character.
863 Note that the root item of the delegate component must be a QDeclarativeItem or
864 QDeclarativeItem derived item.
866 QDeclarativeComponent* QDeclarativeTextEdit::cursorDelegate() const
868 Q_D(const QDeclarativeTextEdit);
869 return d->cursorComponent;
872 void QDeclarativeTextEdit::setCursorDelegate(QDeclarativeComponent* c)
874 Q_D(QDeclarativeTextEdit);
875 if(d->cursorComponent){
877 d->control->setCursorWidth(-1);
878 dirtyCache(cursorRectangle());
883 d->cursorComponent = c;
884 if(c && c->isReady()){
885 loadCursorDelegate();
888 connect(c, SIGNAL(statusChanged()),
889 this, SLOT(loadCursorDelegate()));
892 emit cursorDelegateChanged();
895 void QDeclarativeTextEdit::loadCursorDelegate()
897 Q_D(QDeclarativeTextEdit);
898 if(d->cursorComponent->isLoading())
900 d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this)));
902 d->control->setCursorWidth(0);
903 dirtyCache(cursorRectangle());
904 QDeclarative_setParent_noEvent(d->cursor, this);
905 d->cursor->setParentItem(this);
906 d->cursor->setHeight(QFontMetrics(d->font).height());
907 moveCursorDelegate();
909 qmlInfo(this) << "Error loading cursor delegate.";
914 \qmlproperty int TextEdit::selectionStart
916 The cursor position before the first character in the current selection.
918 This property is read-only. To change the selection, use select(start,end),
919 selectAll(), or selectWord().
921 \sa selectionEnd, cursorPosition, selectedText
923 int QDeclarativeTextEdit::selectionStart() const
925 Q_D(const QDeclarativeTextEdit);
926 return d->control->textCursor().selectionStart();
930 \qmlproperty int TextEdit::selectionEnd
932 The cursor position after the last character in the current selection.
934 This property is read-only. To change the selection, use select(start,end),
935 selectAll(), or selectWord().
937 \sa selectionStart, cursorPosition, selectedText
939 int QDeclarativeTextEdit::selectionEnd() const
941 Q_D(const QDeclarativeTextEdit);
942 return d->control->textCursor().selectionEnd();
946 \qmlproperty string TextEdit::selectedText
948 This read-only property provides the text currently selected in the
951 It is equivalent to the following snippet, but is faster and easier
954 //myTextEdit is the id of the TextEdit
955 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
956 myTextEdit.selectionEnd);
959 QString QDeclarativeTextEdit::selectedText() const
961 Q_D(const QDeclarativeTextEdit);
962 return d->control->textCursor().selectedText();
966 \qmlproperty bool TextEdit::activeFocusOnPress
968 Whether the TextEdit should gain active focus on a mouse press. By default this is
971 bool QDeclarativeTextEdit::focusOnPress() const
973 Q_D(const QDeclarativeTextEdit);
974 return d->focusOnPress;
977 void QDeclarativeTextEdit::setFocusOnPress(bool on)
979 Q_D(QDeclarativeTextEdit);
980 if (d->focusOnPress == on)
982 d->focusOnPress = on;
983 emit activeFocusOnPressChanged(d->focusOnPress);
987 \qmlproperty bool TextEdit::persistentSelection
989 Whether the TextEdit should keep the selection visible when it loses active focus to another
990 item in the scene. By default this is set to true;
992 bool QDeclarativeTextEdit::persistentSelection() const
994 Q_D(const QDeclarativeTextEdit);
995 return d->persistentSelection;
998 void QDeclarativeTextEdit::setPersistentSelection(bool on)
1000 Q_D(QDeclarativeTextEdit);
1001 if (d->persistentSelection == on)
1003 d->persistentSelection = on;
1004 emit persistentSelectionChanged(d->persistentSelection);
1008 \qmlproperty real TextEdit::textMargin
1010 The margin, in pixels, around the text in the TextEdit.
1012 qreal QDeclarativeTextEdit::textMargin() const
1014 Q_D(const QDeclarativeTextEdit);
1015 return d->textMargin;
1018 void QDeclarativeTextEdit::setTextMargin(qreal margin)
1020 Q_D(QDeclarativeTextEdit);
1021 if (d->textMargin == margin)
1023 d->textMargin = margin;
1024 d->document->setDocumentMargin(d->textMargin);
1025 emit textMarginChanged(d->textMargin);
1028 void QDeclarativeTextEdit::geometryChanged(const QRectF &newGeometry,
1029 const QRectF &oldGeometry)
1031 if (newGeometry.width() != oldGeometry.width())
1033 QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
1037 Ensures any delayed caching or data loading the class
1038 needs to performed is complete.
1040 void QDeclarativeTextEdit::componentComplete()
1042 Q_D(QDeclarativeTextEdit);
1043 QDeclarativePaintedItem::componentComplete();
1045 d->determineHorizontalAlignment();
1046 d->updateDefaultTextOption();
1053 \qmlproperty bool TextEdit::selectByMouse
1057 If true, the user can use the mouse to select text in some
1058 platform-specific way. Note that for some platforms this may
1059 not be an appropriate interaction (eg. may conflict with how
1060 the text needs to behave inside a Flickable.
1062 bool QDeclarativeTextEdit::selectByMouse() const
1064 Q_D(const QDeclarativeTextEdit);
1065 return d->selectByMouse;
1068 void QDeclarativeTextEdit::setSelectByMouse(bool on)
1070 Q_D(QDeclarativeTextEdit);
1071 if (d->selectByMouse != on) {
1072 d->selectByMouse = on;
1073 setKeepMouseGrab(on);
1075 setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1077 setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1078 emit selectByMouseChanged(on);
1084 \qmlproperty enum TextEdit::mouseSelectionMode
1087 Specifies how text should be selected using a mouse.
1090 \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1091 \o TextEdit.SelectWords - The selection is updated with whole words.
1094 This property only applies when \l selectByMouse is true.
1097 QDeclarativeTextEdit::SelectionMode QDeclarativeTextEdit::mouseSelectionMode() const
1099 Q_D(const QDeclarativeTextEdit);
1100 return d->mouseSelectionMode;
1103 void QDeclarativeTextEdit::setMouseSelectionMode(SelectionMode mode)
1105 Q_D(QDeclarativeTextEdit);
1106 if (d->mouseSelectionMode != mode) {
1107 d->mouseSelectionMode = mode;
1108 d->control->setWordSelectionEnabled(mode == SelectWords);
1109 emit mouseSelectionModeChanged(mode);
1114 \qmlproperty bool TextEdit::readOnly
1116 Whether the user an interact with the TextEdit item. If this
1117 property is set to true the text cannot be edited by user interaction.
1119 By default this property is false.
1121 void QDeclarativeTextEdit::setReadOnly(bool r)
1123 Q_D(QDeclarativeTextEdit);
1124 if (r == isReadOnly())
1127 setFlag(QGraphicsItem::ItemAcceptsInputMethod, !r);
1129 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1130 if (d->selectByMouse)
1131 flags = flags | Qt::TextSelectableByMouse;
1133 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1134 d->control->setTextInteractionFlags(flags);
1136 d->control->moveCursor(QTextCursor::End);
1138 emit readOnlyChanged(r);
1141 bool QDeclarativeTextEdit::isReadOnly() const
1143 Q_D(const QDeclarativeTextEdit);
1144 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1148 Sets how the text edit should interact with user input to the given
1151 void QDeclarativeTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1153 Q_D(QDeclarativeTextEdit);
1154 d->control->setTextInteractionFlags(flags);
1158 Returns the flags specifying how the text edit should interact
1161 Qt::TextInteractionFlags QDeclarativeTextEdit::textInteractionFlags() const
1163 Q_D(const QDeclarativeTextEdit);
1164 return d->control->textInteractionFlags();
1168 \qmlproperty rectangle TextEdit::cursorRectangle
1170 The rectangle where the text cursor is rendered
1171 within the text edit. Read-only.
1173 QRect QDeclarativeTextEdit::cursorRectangle() const
1175 Q_D(const QDeclarativeTextEdit);
1176 return d->control->cursorRect().toRect().translated(0,d->yoff);
1182 Handles the given \a event.
1184 bool QDeclarativeTextEdit::event(QEvent *event)
1186 Q_D(QDeclarativeTextEdit);
1187 if (event->type() == QEvent::ShortcutOverride) {
1188 d->control->processEvent(event, QPointF(0, -d->yoff));
1189 return event->isAccepted();
1191 return QDeclarativePaintedItem::event(event);
1196 Handles the given key \a event.
1198 void QDeclarativeTextEdit::keyPressEvent(QKeyEvent *event)
1200 Q_D(QDeclarativeTextEdit);
1201 keyPressPreHandler(event);
1202 if (!event->isAccepted())
1203 d->control->processEvent(event, QPointF(0, -d->yoff));
1204 if (!event->isAccepted())
1205 QDeclarativePaintedItem::keyPressEvent(event);
1210 Handles the given key \a event.
1212 void QDeclarativeTextEdit::keyReleaseEvent(QKeyEvent *event)
1214 Q_D(QDeclarativeTextEdit);
1215 keyReleasePreHandler(event);
1216 if (!event->isAccepted())
1217 d->control->processEvent(event, QPointF(0, -d->yoff));
1218 if (!event->isAccepted())
1219 QDeclarativePaintedItem::keyReleaseEvent(event);
1222 void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus)
1224 Q_Q(QDeclarativeTextEdit);
1225 q->setCursorVisible(hasFocus && scene && scene->hasFocus());
1226 QDeclarativeItemPrivate::focusChanged(hasFocus);
1230 \qmlmethod void TextEdit::deselect()
1233 Removes active text selection.
1235 void QDeclarativeTextEdit::deselect()
1237 Q_D(QDeclarativeTextEdit);
1238 QTextCursor c = d->control->textCursor();
1240 d->control->setTextCursor(c);
1244 \qmlmethod void TextEdit::selectAll()
1246 Causes all text to be selected.
1248 void QDeclarativeTextEdit::selectAll()
1250 Q_D(QDeclarativeTextEdit);
1251 d->control->selectAll();
1255 \qmlmethod void TextEdit::selectWord()
1257 Causes the word closest to the current cursor position to be selected.
1259 void QDeclarativeTextEdit::selectWord()
1261 Q_D(QDeclarativeTextEdit);
1262 QTextCursor c = d->control->textCursor();
1263 c.select(QTextCursor::WordUnderCursor);
1264 d->control->setTextCursor(c);
1268 \qmlmethod void TextEdit::select(int start, int end)
1270 Causes the text from \a start to \a end to be selected.
1272 If either start or end is out of range, the selection is not changed.
1274 After calling this, selectionStart will become the lesser
1275 and selectionEnd will become the greater (regardless of the order passed
1278 \sa selectionStart, selectionEnd
1280 void QDeclarativeTextEdit::select(int start, int end)
1282 Q_D(QDeclarativeTextEdit);
1283 if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
1285 QTextCursor cursor = d->control->textCursor();
1286 cursor.beginEditBlock();
1287 cursor.setPosition(start, QTextCursor::MoveAnchor);
1288 cursor.setPosition(end, QTextCursor::KeepAnchor);
1289 cursor.endEditBlock();
1290 d->control->setTextCursor(cursor);
1293 updateSelectionMarkers();
1297 \qmlmethod void TextEdit::isRightToLeft(int start, int end)
1299 Returns true if the natural reading direction of the editor text
1300 found between positions \a start and \a end is right to left.
1302 bool QDeclarativeTextEdit::isRightToLeft(int start, int end)
1304 Q_D(QDeclarativeTextEdit);
1306 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1309 return d->text.mid(start, end - start).isRightToLeft();
1313 #ifndef QT_NO_CLIPBOARD
1315 \qmlmethod TextEdit::cut()
1317 Moves the currently selected text to the system clipboard.
1319 void QDeclarativeTextEdit::cut()
1321 Q_D(QDeclarativeTextEdit);
1326 \qmlmethod TextEdit::copy()
1328 Copies the currently selected text to the system clipboard.
1330 void QDeclarativeTextEdit::copy()
1332 Q_D(QDeclarativeTextEdit);
1337 \qmlmethod TextEdit::paste()
1339 Replaces the currently selected text by the contents of the system clipboard.
1341 void QDeclarativeTextEdit::paste()
1343 Q_D(QDeclarativeTextEdit);
1344 d->control->paste();
1346 #endif // QT_NO_CLIPBOARD
1350 Handles the given mouse \a event.
1352 void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
1354 Q_D(QDeclarativeTextEdit);
1355 if (d->focusOnPress){
1356 bool hadActiveFocus = hasActiveFocus();
1358 if (d->showInputPanelOnFocus) {
1359 if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1360 // re-open input panel on press if already focused
1361 openSoftwareInputPanel();
1363 } else { // show input panel on click
1364 if (hasActiveFocus() && !hadActiveFocus) {
1365 d->clickCausedFocus = true;
1370 d->control->processEvent(event, QPointF(0, -d->yoff));
1371 if (!event->isAccepted())
1372 QDeclarativePaintedItem::mousePressEvent(event);
1377 Handles the given mouse \a event.
1379 void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1381 Q_D(QDeclarativeTextEdit);
1382 d->control->processEvent(event, QPointF(0, -d->yoff));
1383 if (!d->showInputPanelOnFocus) { // input panel on click
1384 if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1385 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1386 if (view->scene() && view->scene() == scene()) {
1387 qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1392 d->clickCausedFocus = false;
1394 if (!event->isAccepted())
1395 QDeclarativePaintedItem::mouseReleaseEvent(event);
1400 Handles the given mouse \a event.
1402 void QDeclarativeTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1404 Q_D(QDeclarativeTextEdit);
1406 d->control->processEvent(event, QPointF(0, -d->yoff));
1407 if (!event->isAccepted())
1408 QDeclarativePaintedItem::mouseDoubleClickEvent(event);
1414 Handles the given mouse \a event.
1416 void QDeclarativeTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1418 Q_D(QDeclarativeTextEdit);
1419 d->control->processEvent(event, QPointF(0, -d->yoff));
1420 if (!event->isAccepted())
1421 QDeclarativePaintedItem::mouseMoveEvent(event);
1426 Handles the given input method \a event.
1428 void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event)
1430 Q_D(QDeclarativeTextEdit);
1431 const bool wasComposing = isInputMethodComposing();
1432 d->control->processEvent(event, QPointF(0, -d->yoff));
1433 if (wasComposing != isInputMethodComposing())
1434 emit inputMethodComposingChanged();
1439 Returns the value of the given \a property.
1441 QVariant QDeclarativeTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1443 Q_D(const QDeclarativeTextEdit);
1444 return d->control->inputMethodQuery(property);
1448 Draws the contents of the text edit using the given \a painter within
1449 the given \a bounds.
1451 void QDeclarativeTextEdit::drawContents(QPainter *painter, const QRect &bounds)
1453 Q_D(QDeclarativeTextEdit);
1455 painter->setRenderHint(QPainter::TextAntialiasing, true);
1456 painter->translate(0,d->yoff);
1458 d->control->drawContents(painter, bounds.translated(0,-d->yoff));
1460 painter->translate(0,-d->yoff);
1463 void QDeclarativeTextEdit::updateImgCache(const QRectF &rf)
1465 Q_D(const QDeclarativeTextEdit);
1467 if (!rf.isValid()) {
1468 r = QRect(0,0,INT_MAX,INT_MAX);
1471 if (r.height() > INT_MAX/2) {
1472 // Take care of overflow when translating "everything"
1473 r.setTop(r.y() + d->yoff);
1474 r.setBottom(INT_MAX/2);
1476 r = r.translated(0,d->yoff);
1484 \qmlproperty bool TextEdit::smooth
1486 This property holds whether the text is smoothly scaled or transformed.
1488 Smooth filtering gives better visual quality, but is slower. If
1489 the item is displayed at its natural size, this property has no visual or
1492 \note Generally scaling artifacts are only visible if the item is stationary on
1493 the screen. A common pattern when animating an item is to disable smooth
1494 filtering at the beginning of the animation and reenable it at the conclusion.
1498 \qmlproperty bool TextEdit::canPaste
1501 Returns true if the TextEdit is writable and the content of the clipboard is
1502 suitable for pasting into the TextEdit.
1504 bool QDeclarativeTextEdit::canPaste() const
1506 Q_D(const QDeclarativeTextEdit);
1511 \qmlproperty bool TextEdit::inputMethodComposing
1515 This property holds whether the TextEdit has partial text input from an
1518 While it is composing an input method may rely on mouse or key events from
1519 the TextEdit to edit or commit the partial text. This property can be used
1520 to determine when to disable events handlers that may interfere with the
1521 correct operation of an input method.
1523 bool QDeclarativeTextEdit::isInputMethodComposing() const
1525 Q_D(const QDeclarativeTextEdit);
1526 if (QTextLayout *layout = d->control->textCursor().block().layout())
1527 return layout->preeditAreaText().length() > 0;
1531 void QDeclarativeTextEditPrivate::init()
1533 Q_Q(QDeclarativeTextEdit);
1535 q->setSmooth(smooth);
1536 q->setAcceptedMouseButtons(Qt::LeftButton);
1537 q->setFlag(QGraphicsItem::ItemHasNoContents, false);
1538 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
1540 control = new QTextControl(q);
1541 control->setIgnoreUnusedNavigationEvents(true);
1542 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1543 control->setDragEnabled(false);
1545 // QTextControl follows the default text color
1546 // defined by the platform, declarative text
1547 // should be black by default
1548 QPalette pal = control->palette();
1549 if (pal.color(QPalette::Text) != color) {
1550 pal.setColor(QPalette::Text, color);
1551 control->setPalette(pal);
1554 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF)));
1556 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1557 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1558 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1559 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1560 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1561 QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate()));
1562 QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1563 #ifndef QT_NO_CLIPBOARD
1564 QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged()));
1565 QObject::connect(QApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1566 canPaste = control->canPaste();
1569 document = control->document();
1570 document->setDefaultFont(font);
1571 document->setDocumentMargin(textMargin);
1572 document->setUndoRedoEnabled(false); // flush undo buffer.
1573 document->setUndoRedoEnabled(true);
1574 updateDefaultTextOption();
1577 void QDeclarativeTextEdit::q_textChanged()
1579 Q_D(QDeclarativeTextEdit);
1581 d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
1582 d->determineHorizontalAlignment();
1583 d->updateDefaultTextOption();
1586 emit textChanged(d->text);
1589 void QDeclarativeTextEdit::moveCursorDelegate()
1591 Q_D(QDeclarativeTextEdit);
1592 d->determineHorizontalAlignment();
1594 emit cursorRectangleChanged();
1597 QRectF cursorRect = cursorRectangle();
1598 d->cursor->setX(cursorRect.x());
1599 d->cursor->setY(cursorRect.y());
1602 void QDeclarativeTextEditPrivate::updateSelection()
1604 Q_Q(QDeclarativeTextEdit);
1605 QTextCursor cursor = control->textCursor();
1606 bool startChange = (lastSelectionStart != cursor.selectionStart());
1607 bool endChange = (lastSelectionEnd != cursor.selectionEnd());
1608 cursor.beginEditBlock();
1609 cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
1610 cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
1611 cursor.endEditBlock();
1612 control->setTextCursor(cursor);
1614 q->selectionStartChanged();
1616 q->selectionEndChanged();
1619 void QDeclarativeTextEdit::updateSelectionMarkers()
1621 Q_D(QDeclarativeTextEdit);
1622 if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
1623 d->lastSelectionStart = d->control->textCursor().selectionStart();
1624 emit selectionStartChanged();
1626 if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
1627 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1628 emit selectionEndChanged();
1632 QRectF QDeclarativeTextEdit::boundingRect() const
1634 Q_D(const QDeclarativeTextEdit);
1635 QRectF r = QDeclarativePaintedItem::boundingRect();
1636 int cursorWidth = 1;
1638 cursorWidth = d->cursor->width();
1639 if(!d->document->isEmpty())
1640 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1642 // Could include font max left/right bearings to either side of rectangle.
1644 r.setRight(r.right() + cursorWidth);
1645 return r.translated(0,d->yoff);
1648 qreal QDeclarativeTextEditPrivate::implicitWidth() const
1650 Q_Q(const QDeclarativeTextEdit);
1651 if (!requireImplicitWidth) {
1652 // We don't calculate implicitWidth unless it is required.
1653 // We need to force a size update now to ensure implicitWidth is calculated
1654 const_cast<QDeclarativeTextEditPrivate*>(this)->requireImplicitWidth = true;
1655 const_cast<QDeclarativeTextEdit*>(q)->updateSize();
1657 return mImplicitWidth;
1660 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1661 // need to do all the calculations each time
1662 void QDeclarativeTextEdit::updateSize()
1664 Q_D(QDeclarativeTextEdit);
1665 if (isComponentComplete()) {
1666 qreal naturalWidth = d->mImplicitWidth;
1667 // ### assumes that if the width is set, the text will fill to edges
1668 // ### (unless wrap is false, then clipping will occur)
1670 if (!d->requireImplicitWidth) {
1671 emit implicitWidthChanged();
1672 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1673 if (d->requireImplicitWidth)
1676 if (d->requireImplicitWidth) {
1677 d->document->setTextWidth(-1);
1678 naturalWidth = d->document->idealWidth();
1680 if (d->document->textWidth() != width())
1681 d->document->setTextWidth(width());
1683 d->document->setTextWidth(-1);
1685 QFontMetrics fm = QFontMetrics(d->font);
1687 dy -= (int)d->document->size().height();
1690 if (heightValid()) {
1691 if (d->vAlign == AlignBottom)
1693 else if (d->vAlign == AlignVCenter)
1700 if (nyoff != d->yoff) {
1701 prepareGeometryChange();
1704 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1706 //### need to comfirm cost of always setting these
1707 int newWidth = qCeil(d->document->idealWidth());
1708 if (!widthValid() && d->document->textWidth() != newWidth)
1709 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1710 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1712 setImplicitWidth(newWidth);
1713 else if (d->requireImplicitWidth)
1714 setImplicitWidth(naturalWidth);
1715 qreal newHeight = d->document->size().height();
1717 newHeight = fm.height();
1718 setImplicitHeight(newHeight);
1720 d->paintedSize = QSize(newWidth, newHeight);
1721 setContentsSize(d->paintedSize);
1722 emit paintedSizeChanged();
1729 void QDeclarativeTextEdit::updateTotalLines()
1731 Q_D(QDeclarativeTextEdit);
1735 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1736 QTextLayout *layout = it.layout();
1739 subLines += layout->lineCount()-1;
1742 int newTotalLines = d->document->lineCount() + subLines;
1743 if (d->lineCount != newTotalLines) {
1744 d->lineCount = newTotalLines;
1745 emit lineCountChanged();
1749 void QDeclarativeTextEditPrivate::updateDefaultTextOption()
1751 Q_Q(QDeclarativeTextEdit);
1752 QTextOption opt = document->defaultTextOption();
1753 int oldAlignment = opt.alignment();
1755 QDeclarativeTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
1756 if (rightToLeftText) {
1757 if (horizontalAlignment == QDeclarativeTextEdit::AlignLeft)
1758 horizontalAlignment = QDeclarativeTextEdit::AlignRight;
1759 else if (horizontalAlignment == QDeclarativeTextEdit::AlignRight)
1760 horizontalAlignment = QDeclarativeTextEdit::AlignLeft;
1762 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
1764 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1765 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
1767 if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
1769 document->setDefaultTextOption(opt);
1774 \qmlmethod void TextEdit::openSoftwareInputPanel()
1776 Opens software input panels like virtual keyboards for typing, useful for
1777 customizing when you want the input keyboard to be shown and hidden in
1780 By default the opening of input panels follows the platform style. On Symbian^1 and
1781 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1782 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1783 always closed if no editor has active focus.
1785 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1786 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1787 the behavior you want.
1789 Only relevant on platforms, which provide virtual keyboards.
1795 text: "Hello world!"
1796 activeFocusOnPress: false
1798 anchors.fill: parent
1800 if (!textEdit.activeFocus) {
1801 textEdit.forceActiveFocus();
1802 textEdit.openSoftwareInputPanel();
1804 textEdit.focus = false;
1807 onPressAndHold: textEdit.closeSoftwareInputPanel();
1812 void QDeclarativeTextEdit::openSoftwareInputPanel()
1814 QEvent event(QEvent::RequestSoftwareInputPanel);
1816 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1817 if (view->scene() && view->scene() == scene()) {
1818 QApplication::sendEvent(view, &event);
1825 \qmlmethod void TextEdit::closeSoftwareInputPanel()
1827 Closes a software input panel like a virtual keyboard shown on the screen, useful
1828 for customizing when you want the input keyboard to be shown and hidden in
1831 By default the opening of input panels follows the platform style. On Symbian^1 and
1832 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1833 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1834 always closed if no editor has active focus.
1836 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1837 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1838 the behavior you want.
1840 Only relevant on platforms, which provide virtual keyboards.
1846 text: "Hello world!"
1847 activeFocusOnPress: false
1849 anchors.fill: parent
1851 if (!textEdit.activeFocus) {
1852 textEdit.forceActiveFocus();
1853 textEdit.openSoftwareInputPanel();
1855 textEdit.focus = false;
1858 onPressAndHold: textEdit.closeSoftwareInputPanel();
1863 void QDeclarativeTextEdit::closeSoftwareInputPanel()
1865 QEvent event(QEvent::CloseSoftwareInputPanel);
1867 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1868 if (view->scene() && view->scene() == scene()) {
1869 QApplication::sendEvent(view, &event);
1875 void QDeclarativeTextEdit::focusInEvent(QFocusEvent *event)
1877 Q_D(const QDeclarativeTextEdit);
1878 if (d->showInputPanelOnFocus) {
1879 if (d->focusOnPress && !isReadOnly()) {
1880 openSoftwareInputPanel();
1883 QDeclarativePaintedItem::focusInEvent(event);
1886 void QDeclarativeTextEdit::q_canPasteChanged()
1888 Q_D(QDeclarativeTextEdit);
1889 bool old = d->canPaste;
1890 d->canPaste = d->control->canPaste();
1891 if(old!=d->canPaste)
1892 emit canPasteChanged();