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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
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
276 \o TextEdit.StyledText
279 The default is TextEdit.AutoText. If the text format is TextEdit.AutoText the text edit
280 will automatically determine whether the text should be treated as
281 rich text. This determination is made using Qt::mightBeRichText().
290 text: "<b>Hello</b> <i>World!</i>"
294 textFormat: TextEdit.RichText
295 text: "<b>Hello</b> <i>World!</i>"
299 textFormat: TextEdit.PlainText
300 text: "<b>Hello</b> <i>World!</i>"
304 \o \image declarative-textformat.png
307 QDeclarativeTextEdit::TextFormat QDeclarativeTextEdit::textFormat() const
309 Q_D(const QDeclarativeTextEdit);
313 void QDeclarativeTextEdit::setTextFormat(TextFormat format)
315 Q_D(QDeclarativeTextEdit);
316 if (format == d->format)
318 bool wasRich = d->richText;
319 d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
321 if (wasRich && !d->richText) {
322 d->control->setPlainText(d->text);
324 } else if (!wasRich && d->richText) {
325 #ifndef QT_NO_TEXTHTMLPARSER
326 d->control->setHtml(d->text);
328 d->control->setPlainText(d->text);
333 d->control->setAcceptRichText(d->format != PlainText);
334 emit textFormatChanged(d->format);
337 QFont QDeclarativeTextEdit::font() const
339 Q_D(const QDeclarativeTextEdit);
340 return d->sourceFont;
343 void QDeclarativeTextEdit::setFont(const QFont &font)
345 Q_D(QDeclarativeTextEdit);
346 if (d->sourceFont == font)
349 d->sourceFont = font;
350 QFont oldFont = d->font;
352 if (d->font.pointSizeF() != -1) {
354 qreal size = qRound(d->font.pointSizeF()*2.0);
355 d->font.setPointSizeF(size/2.0);
358 if (oldFont != d->font) {
360 d->document->setDefaultFont(d->font);
362 d->cursor->setHeight(QFontMetrics(d->font).height());
363 moveCursorDelegate();
368 emit fontChanged(d->sourceFont);
372 \qmlproperty color TextEdit::color
377 // green text using hexadecimal notation
378 TextEdit { color: "#00FF00" }
382 // steelblue text using SVG color name
383 TextEdit { color: "steelblue" }
386 QColor QDeclarativeTextEdit::color() const
388 Q_D(const QDeclarativeTextEdit);
392 void QDeclarativeTextEdit::setColor(const QColor &color)
394 Q_D(QDeclarativeTextEdit);
395 if (d->color == color)
400 QPalette pal = d->control->palette();
401 pal.setColor(QPalette::Text, color);
402 d->control->setPalette(pal);
404 emit colorChanged(d->color);
408 \qmlproperty color TextEdit::selectionColor
410 The text highlight color, used behind selections.
412 QColor QDeclarativeTextEdit::selectionColor() const
414 Q_D(const QDeclarativeTextEdit);
415 return d->selectionColor;
418 void QDeclarativeTextEdit::setSelectionColor(const QColor &color)
420 Q_D(QDeclarativeTextEdit);
421 if (d->selectionColor == color)
425 d->selectionColor = color;
426 QPalette pal = d->control->palette();
427 pal.setColor(QPalette::Highlight, color);
428 d->control->setPalette(pal);
430 emit selectionColorChanged(d->selectionColor);
434 \qmlproperty color TextEdit::selectedTextColor
436 The selected text color, used in selections.
438 QColor QDeclarativeTextEdit::selectedTextColor() const
440 Q_D(const QDeclarativeTextEdit);
441 return d->selectedTextColor;
444 void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color)
446 Q_D(QDeclarativeTextEdit);
447 if (d->selectedTextColor == color)
451 d->selectedTextColor = color;
452 QPalette pal = d->control->palette();
453 pal.setColor(QPalette::HighlightedText, color);
454 d->control->setPalette(pal);
456 emit selectedTextColorChanged(d->selectedTextColor);
460 \qmlproperty enumeration TextEdit::horizontalAlignment
461 \qmlproperty enumeration TextEdit::verticalAlignment
462 \qmlproperty enumeration TextEdit::effectiveHorizontalAlignment
464 Sets the horizontal and vertical alignment of the text within the TextEdit item's
465 width and height. By default, the text alignment follows the natural alignment
466 of the text, for example text that is read from left to right will be aligned to
469 Valid values for \c horizontalAlignment are:
471 \o TextEdit.AlignLeft (default)
472 \o TextEdit.AlignRight
473 \o TextEdit.AlignHCenter
474 \o TextEdit.AlignJustify
477 Valid values for \c verticalAlignment are:
479 \o TextEdit.AlignTop (default)
480 \o TextEdit.AlignBottom
481 \o TextEdit.AlignVCenter
484 When using the attached property LayoutMirroring::enabled to mirror application
485 layouts, the horizontal alignment of text will also be mirrored. However, the property
486 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
487 of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
489 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const
491 Q_D(const QDeclarativeTextEdit);
495 void QDeclarativeTextEdit::setHAlign(HAlignment align)
497 Q_D(QDeclarativeTextEdit);
498 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
499 d->hAlignImplicit = false;
500 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
501 d->updateDefaultTextOption();
506 void QDeclarativeTextEdit::resetHAlign()
508 Q_D(QDeclarativeTextEdit);
509 d->hAlignImplicit = true;
510 if (d->determineHorizontalAlignment() && isComponentComplete()) {
511 d->updateDefaultTextOption();
516 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::effectiveHAlign() const
518 Q_D(const QDeclarativeTextEdit);
519 QDeclarativeTextEdit::HAlignment effectiveAlignment = d->hAlign;
520 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
522 case QDeclarativeTextEdit::AlignLeft:
523 effectiveAlignment = QDeclarativeTextEdit::AlignRight;
525 case QDeclarativeTextEdit::AlignRight:
526 effectiveAlignment = QDeclarativeTextEdit::AlignLeft;
532 return effectiveAlignment;
535 bool QDeclarativeTextEditPrivate::setHAlign(QDeclarativeTextEdit::HAlignment alignment, bool forceAlign)
537 Q_Q(QDeclarativeTextEdit);
538 if (hAlign != alignment || forceAlign) {
539 QDeclarativeTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
541 emit q->horizontalAlignmentChanged(alignment);
542 if (oldEffectiveHAlign != q->effectiveHAlign())
543 emit q->effectiveHorizontalAlignmentChanged();
549 bool QDeclarativeTextEditPrivate::determineHorizontalAlignment()
551 Q_Q(QDeclarativeTextEdit);
552 if (hAlignImplicit && q->isComponentComplete()) {
553 bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
554 return setHAlign(alignToRight ? QDeclarativeTextEdit::AlignRight : QDeclarativeTextEdit::AlignLeft);
559 void QDeclarativeTextEditPrivate::mirrorChange()
561 Q_Q(QDeclarativeTextEdit);
562 if (q->isComponentComplete()) {
563 if (!hAlignImplicit && (hAlign == QDeclarativeTextEdit::AlignRight || hAlign == QDeclarativeTextEdit::AlignLeft)) {
564 updateDefaultTextOption();
566 emit q->effectiveHorizontalAlignmentChanged();
571 QDeclarativeTextEdit::VAlignment QDeclarativeTextEdit::vAlign() const
573 Q_D(const QDeclarativeTextEdit);
577 void QDeclarativeTextEdit::setVAlign(QDeclarativeTextEdit::VAlignment alignment)
579 Q_D(QDeclarativeTextEdit);
580 if (alignment == d->vAlign)
582 d->vAlign = alignment;
583 d->updateDefaultTextOption();
585 moveCursorDelegate();
586 emit verticalAlignmentChanged(d->vAlign);
590 \qmlproperty enumeration TextEdit::wrapMode
592 Set this property to wrap the text to the TextEdit item's width.
593 The text will only wrap if an explicit width has been set.
596 \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
597 \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
598 \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
599 \o TextEdit.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
602 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
604 QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const
606 Q_D(const QDeclarativeTextEdit);
610 void QDeclarativeTextEdit::setWrapMode(WrapMode mode)
612 Q_D(QDeclarativeTextEdit);
613 if (mode == d->wrapMode)
616 d->updateDefaultTextOption();
618 emit wrapModeChanged();
622 \qmlproperty int TextEdit::lineCount
625 Returns the total number of lines in the textEdit item.
627 int QDeclarativeTextEdit::lineCount() const
629 Q_D(const QDeclarativeTextEdit);
634 \qmlproperty real TextEdit::paintedWidth
636 Returns the width of the text, including the width past the width
637 which is covered due to insufficient wrapping if \l wrapMode is set.
639 qreal QDeclarativeTextEdit::paintedWidth() const
641 Q_D(const QDeclarativeTextEdit);
642 return d->paintedSize.width();
646 \qmlproperty real TextEdit::paintedHeight
648 Returns the height of the text, including the height past the height
649 that is covered if the text does not fit within the set height.
651 qreal QDeclarativeTextEdit::paintedHeight() const
653 Q_D(const QDeclarativeTextEdit);
654 return d->paintedSize.height();
658 \qmlmethod rectangle TextEdit::positionToRectangle(position)
660 Returns the rectangle at the given \a position in the text. The x, y,
661 and height properties correspond to the cursor that would describe
664 QRectF QDeclarativeTextEdit::positionToRectangle(int pos) const
666 Q_D(const QDeclarativeTextEdit);
667 QTextCursor c(d->document);
669 return d->control->cursorRect(c);
674 \qmlmethod int TextEdit::positionAt(int x, int y)
676 Returns the text position closest to pixel position (\a x, \a y).
678 Position 0 is before the first character, position 1 is after the first character
679 but before the second, and so on until position \l {text}.length, which is after all characters.
681 int QDeclarativeTextEdit::positionAt(int x, int y) const
683 Q_D(const QDeclarativeTextEdit);
684 int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
685 QTextCursor cursor = d->control->textCursor();
686 if (r > cursor.position()) {
687 // The cursor position includes positions within the preedit text, but only positions in the
688 // same text block are offset so it is possible to get a position that is either part of the
689 // preedit or the next text block.
690 QTextLayout *layout = cursor.block().layout();
691 const int preeditLength = layout
692 ? layout->preeditAreaText().length()
694 if (preeditLength > 0
695 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
696 r = r > cursor.position() + preeditLength
704 void QDeclarativeTextEdit::moveCursorSelection(int pos)
706 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
707 Q_D(QDeclarativeTextEdit);
708 QTextCursor cursor = d->control->textCursor();
709 if (cursor.position() == pos)
711 cursor.setPosition(pos, QTextCursor::KeepAnchor);
712 d->control->setTextCursor(cursor);
716 \qmlmethod void TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
719 Moves the cursor to \a position and updates the selection according to the optional \a mode
720 parameter. (To only move the cursor, set the \l cursorPosition property.)
722 When this method is called it additionally sets either the
723 selectionStart or the selectionEnd (whichever was at the previous cursor position)
724 to the specified position. This allows you to easily extend and contract the selected
727 The selection mode specifies whether the selection is updated on a per character or a per word
728 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
731 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
732 the previous cursor position) to the specified position.
733 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
734 words between the specified postion and the previous cursor position. Words partially in the
738 For example, take this sequence of calls:
742 moveCursorSelection(9, TextEdit.SelectCharacters)
743 moveCursorSelection(7, TextEdit.SelectCharacters)
746 This moves the cursor to position 5, extend the selection end from 5 to 9
747 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
748 selected (the 6th and 7th characters).
750 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
751 before or on position 5 and extend the selection end to a word boundary on or past position 9.
753 void QDeclarativeTextEdit::moveCursorSelection(int pos, SelectionMode mode)
755 Q_D(QDeclarativeTextEdit);
756 QTextCursor cursor = d->control->textCursor();
757 if (cursor.position() == pos)
759 if (mode == SelectCharacters) {
760 cursor.setPosition(pos, QTextCursor::KeepAnchor);
761 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
762 if (cursor.anchor() > cursor.position()) {
763 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
764 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
765 if (cursor.position() == cursor.anchor())
766 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
768 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
770 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
771 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
774 cursor.setPosition(pos, QTextCursor::KeepAnchor);
775 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
776 if (cursor.position() != pos)
777 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
778 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
779 if (cursor.anchor() < cursor.position()) {
780 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
781 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
783 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
784 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
785 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
786 if (cursor.position() != cursor.anchor()) {
787 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
788 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
792 cursor.setPosition(pos, QTextCursor::KeepAnchor);
793 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
794 if (cursor.position() != pos) {
795 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
796 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
799 d->control->setTextCursor(cursor);
803 \qmlproperty bool TextEdit::cursorVisible
804 If true the text edit shows a cursor.
806 This property is set and unset when the text edit gets active focus, but it can also
807 be set directly (useful, for example, if a KeyProxy might forward keys to it).
809 bool QDeclarativeTextEdit::isCursorVisible() const
811 Q_D(const QDeclarativeTextEdit);
812 return d->cursorVisible;
815 void QDeclarativeTextEdit::setCursorVisible(bool on)
817 Q_D(QDeclarativeTextEdit);
818 if (d->cursorVisible == on)
820 d->cursorVisible = on;
821 QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
822 if (!on && !d->persistentSelection)
823 d->control->setCursorIsFocusIndicator(true);
824 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
825 emit cursorVisibleChanged(d->cursorVisible);
829 \qmlproperty int TextEdit::cursorPosition
830 The position of the cursor in the TextEdit.
832 int QDeclarativeTextEdit::cursorPosition() const
834 Q_D(const QDeclarativeTextEdit);
835 return d->control->textCursor().position();
838 void QDeclarativeTextEdit::setCursorPosition(int pos)
840 Q_D(QDeclarativeTextEdit);
841 if (pos < 0 || pos > d->text.length())
843 QTextCursor cursor = d->control->textCursor();
844 if (cursor.position() == pos && cursor.anchor() == pos)
846 cursor.setPosition(pos);
847 d->control->setTextCursor(cursor);
851 \qmlproperty Component TextEdit::cursorDelegate
852 The delegate for the cursor in the TextEdit.
854 If you set a cursorDelegate for a TextEdit, this delegate will be used for
855 drawing the cursor instead of the standard cursor. An instance of the
856 delegate will be created and managed by the text edit when a cursor is
857 needed, and the x and y properties of delegate instance will be set so as
858 to be one pixel before the top left of the current character.
860 Note that the root item of the delegate component must be a QDeclarativeItem or
861 QDeclarativeItem derived item.
863 QDeclarativeComponent* QDeclarativeTextEdit::cursorDelegate() const
865 Q_D(const QDeclarativeTextEdit);
866 return d->cursorComponent;
869 void QDeclarativeTextEdit::setCursorDelegate(QDeclarativeComponent* c)
871 Q_D(QDeclarativeTextEdit);
872 if(d->cursorComponent){
874 d->control->setCursorWidth(-1);
875 dirtyCache(cursorRectangle());
880 d->cursorComponent = c;
881 if(c && c->isReady()){
882 loadCursorDelegate();
885 connect(c, SIGNAL(statusChanged()),
886 this, SLOT(loadCursorDelegate()));
889 emit cursorDelegateChanged();
892 void QDeclarativeTextEdit::loadCursorDelegate()
894 Q_D(QDeclarativeTextEdit);
895 if(d->cursorComponent->isLoading())
897 d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this)));
899 d->control->setCursorWidth(0);
900 dirtyCache(cursorRectangle());
901 QDeclarative_setParent_noEvent(d->cursor, this);
902 d->cursor->setParentItem(this);
903 d->cursor->setHeight(QFontMetrics(d->font).height());
904 moveCursorDelegate();
906 qmlInfo(this) << "Error loading cursor delegate.";
911 \qmlproperty int TextEdit::selectionStart
913 The cursor position before the first character in the current selection.
915 This property is read-only. To change the selection, use select(start,end),
916 selectAll(), or selectWord().
918 \sa selectionEnd, cursorPosition, selectedText
920 int QDeclarativeTextEdit::selectionStart() const
922 Q_D(const QDeclarativeTextEdit);
923 return d->control->textCursor().selectionStart();
927 \qmlproperty int TextEdit::selectionEnd
929 The cursor position after the last character in the current selection.
931 This property is read-only. To change the selection, use select(start,end),
932 selectAll(), or selectWord().
934 \sa selectionStart, cursorPosition, selectedText
936 int QDeclarativeTextEdit::selectionEnd() const
938 Q_D(const QDeclarativeTextEdit);
939 return d->control->textCursor().selectionEnd();
943 \qmlproperty string TextEdit::selectedText
945 This read-only property provides the text currently selected in the
948 It is equivalent to the following snippet, but is faster and easier
951 //myTextEdit is the id of the TextEdit
952 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
953 myTextEdit.selectionEnd);
956 QString QDeclarativeTextEdit::selectedText() const
958 Q_D(const QDeclarativeTextEdit);
959 return d->control->textCursor().selectedText();
963 \qmlproperty bool TextEdit::activeFocusOnPress
965 Whether the TextEdit should gain active focus on a mouse press. By default this is
968 bool QDeclarativeTextEdit::focusOnPress() const
970 Q_D(const QDeclarativeTextEdit);
971 return d->focusOnPress;
974 void QDeclarativeTextEdit::setFocusOnPress(bool on)
976 Q_D(QDeclarativeTextEdit);
977 if (d->focusOnPress == on)
979 d->focusOnPress = on;
980 emit activeFocusOnPressChanged(d->focusOnPress);
984 \qmlproperty bool TextEdit::persistentSelection
986 Whether the TextEdit should keep the selection visible when it loses active focus to another
987 item in the scene. By default this is set to true;
989 bool QDeclarativeTextEdit::persistentSelection() const
991 Q_D(const QDeclarativeTextEdit);
992 return d->persistentSelection;
995 void QDeclarativeTextEdit::setPersistentSelection(bool on)
997 Q_D(QDeclarativeTextEdit);
998 if (d->persistentSelection == on)
1000 d->persistentSelection = on;
1001 emit persistentSelectionChanged(d->persistentSelection);
1005 \qmlproperty real TextEdit::textMargin
1007 The margin, in pixels, around the text in the TextEdit.
1009 qreal QDeclarativeTextEdit::textMargin() const
1011 Q_D(const QDeclarativeTextEdit);
1012 return d->textMargin;
1015 void QDeclarativeTextEdit::setTextMargin(qreal margin)
1017 Q_D(QDeclarativeTextEdit);
1018 if (d->textMargin == margin)
1020 d->textMargin = margin;
1021 d->document->setDocumentMargin(d->textMargin);
1022 emit textMarginChanged(d->textMargin);
1025 void QDeclarativeTextEdit::geometryChanged(const QRectF &newGeometry,
1026 const QRectF &oldGeometry)
1028 if (newGeometry.width() != oldGeometry.width())
1030 QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
1034 Ensures any delayed caching or data loading the class
1035 needs to performed is complete.
1037 void QDeclarativeTextEdit::componentComplete()
1039 Q_D(QDeclarativeTextEdit);
1040 QDeclarativePaintedItem::componentComplete();
1042 d->determineHorizontalAlignment();
1043 d->updateDefaultTextOption();
1050 \qmlproperty bool TextEdit::selectByMouse
1054 If true, the user can use the mouse to select text in some
1055 platform-specific way. Note that for some platforms this may
1056 not be an appropriate interaction (eg. may conflict with how
1057 the text needs to behave inside a Flickable.
1059 bool QDeclarativeTextEdit::selectByMouse() const
1061 Q_D(const QDeclarativeTextEdit);
1062 return d->selectByMouse;
1065 void QDeclarativeTextEdit::setSelectByMouse(bool on)
1067 Q_D(QDeclarativeTextEdit);
1068 if (d->selectByMouse != on) {
1069 d->selectByMouse = on;
1070 setKeepMouseGrab(on);
1072 setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1074 setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1075 emit selectByMouseChanged(on);
1081 \qmlproperty enum TextEdit::mouseSelectionMode
1084 Specifies how text should be selected using a mouse.
1087 \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1088 \o TextEdit.SelectWords - The selection is updated with whole words.
1091 This property only applies when \l selectByMouse is true.
1094 QDeclarativeTextEdit::SelectionMode QDeclarativeTextEdit::mouseSelectionMode() const
1096 Q_D(const QDeclarativeTextEdit);
1097 return d->mouseSelectionMode;
1100 void QDeclarativeTextEdit::setMouseSelectionMode(SelectionMode mode)
1102 Q_D(QDeclarativeTextEdit);
1103 if (d->mouseSelectionMode != mode) {
1104 d->mouseSelectionMode = mode;
1105 d->control->setWordSelectionEnabled(mode == SelectWords);
1106 emit mouseSelectionModeChanged(mode);
1111 \qmlproperty bool TextEdit::readOnly
1113 Whether the user an interact with the TextEdit item. If this
1114 property is set to true the text cannot be edited by user interaction.
1116 By default this property is false.
1118 void QDeclarativeTextEdit::setReadOnly(bool r)
1120 Q_D(QDeclarativeTextEdit);
1121 if (r == isReadOnly())
1124 setFlag(QGraphicsItem::ItemAcceptsInputMethod, !r);
1126 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1127 if (d->selectByMouse)
1128 flags = flags | Qt::TextSelectableByMouse;
1130 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1131 d->control->setTextInteractionFlags(flags);
1133 d->control->moveCursor(QTextCursor::End);
1135 emit readOnlyChanged(r);
1138 bool QDeclarativeTextEdit::isReadOnly() const
1140 Q_D(const QDeclarativeTextEdit);
1141 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1145 Sets how the text edit should interact with user input to the given
1148 void QDeclarativeTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1150 Q_D(QDeclarativeTextEdit);
1151 d->control->setTextInteractionFlags(flags);
1155 Returns the flags specifying how the text edit should interact
1158 Qt::TextInteractionFlags QDeclarativeTextEdit::textInteractionFlags() const
1160 Q_D(const QDeclarativeTextEdit);
1161 return d->control->textInteractionFlags();
1165 \qmlproperty rectangle TextEdit::cursorRectangle
1167 The rectangle where the text cursor is rendered
1168 within the text edit. Read-only.
1170 QRect QDeclarativeTextEdit::cursorRectangle() const
1172 Q_D(const QDeclarativeTextEdit);
1173 return d->control->cursorRect().toRect().translated(0,d->yoff);
1179 Handles the given \a event.
1181 bool QDeclarativeTextEdit::event(QEvent *event)
1183 Q_D(QDeclarativeTextEdit);
1184 if (event->type() == QEvent::ShortcutOverride) {
1185 d->control->processEvent(event, QPointF(0, -d->yoff));
1186 return event->isAccepted();
1188 return QDeclarativePaintedItem::event(event);
1193 Handles the given key \a event.
1195 void QDeclarativeTextEdit::keyPressEvent(QKeyEvent *event)
1197 Q_D(QDeclarativeTextEdit);
1198 keyPressPreHandler(event);
1199 if (!event->isAccepted())
1200 d->control->processEvent(event, QPointF(0, -d->yoff));
1201 if (!event->isAccepted())
1202 QDeclarativePaintedItem::keyPressEvent(event);
1207 Handles the given key \a event.
1209 void QDeclarativeTextEdit::keyReleaseEvent(QKeyEvent *event)
1211 Q_D(QDeclarativeTextEdit);
1212 keyReleasePreHandler(event);
1213 if (!event->isAccepted())
1214 d->control->processEvent(event, QPointF(0, -d->yoff));
1215 if (!event->isAccepted())
1216 QDeclarativePaintedItem::keyReleaseEvent(event);
1219 void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus)
1221 Q_Q(QDeclarativeTextEdit);
1222 q->setCursorVisible(hasFocus && scene && scene->hasFocus());
1223 QDeclarativeItemPrivate::focusChanged(hasFocus);
1227 \qmlmethod void TextEdit::deselect()
1230 Removes active text selection.
1232 void QDeclarativeTextEdit::deselect()
1234 Q_D(QDeclarativeTextEdit);
1235 QTextCursor c = d->control->textCursor();
1237 d->control->setTextCursor(c);
1241 \qmlmethod void TextEdit::selectAll()
1243 Causes all text to be selected.
1245 void QDeclarativeTextEdit::selectAll()
1247 Q_D(QDeclarativeTextEdit);
1248 d->control->selectAll();
1252 \qmlmethod void TextEdit::selectWord()
1254 Causes the word closest to the current cursor position to be selected.
1256 void QDeclarativeTextEdit::selectWord()
1258 Q_D(QDeclarativeTextEdit);
1259 QTextCursor c = d->control->textCursor();
1260 c.select(QTextCursor::WordUnderCursor);
1261 d->control->setTextCursor(c);
1265 \qmlmethod void TextEdit::select(int start, int end)
1267 Causes the text from \a start to \a end to be selected.
1269 If either start or end is out of range, the selection is not changed.
1271 After calling this, selectionStart will become the lesser
1272 and selectionEnd will become the greater (regardless of the order passed
1275 \sa selectionStart, selectionEnd
1277 void QDeclarativeTextEdit::select(int start, int end)
1279 Q_D(QDeclarativeTextEdit);
1280 if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
1282 QTextCursor cursor = d->control->textCursor();
1283 cursor.beginEditBlock();
1284 cursor.setPosition(start, QTextCursor::MoveAnchor);
1285 cursor.setPosition(end, QTextCursor::KeepAnchor);
1286 cursor.endEditBlock();
1287 d->control->setTextCursor(cursor);
1290 updateSelectionMarkers();
1294 \qmlmethod void TextEdit::isRightToLeft(int start, int end)
1296 Returns true if the natural reading direction of the editor text
1297 found between positions \a start and \a end is right to left.
1299 bool QDeclarativeTextEdit::isRightToLeft(int start, int end)
1301 Q_D(QDeclarativeTextEdit);
1303 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1306 return d->text.mid(start, end - start).isRightToLeft();
1310 #ifndef QT_NO_CLIPBOARD
1312 \qmlmethod TextEdit::cut()
1314 Moves the currently selected text to the system clipboard.
1316 void QDeclarativeTextEdit::cut()
1318 Q_D(QDeclarativeTextEdit);
1323 \qmlmethod TextEdit::copy()
1325 Copies the currently selected text to the system clipboard.
1327 void QDeclarativeTextEdit::copy()
1329 Q_D(QDeclarativeTextEdit);
1334 \qmlmethod TextEdit::paste()
1336 Replaces the currently selected text by the contents of the system clipboard.
1338 void QDeclarativeTextEdit::paste()
1340 Q_D(QDeclarativeTextEdit);
1341 d->control->paste();
1343 #endif // QT_NO_CLIPBOARD
1347 Handles the given mouse \a event.
1349 void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
1351 Q_D(QDeclarativeTextEdit);
1352 if (d->focusOnPress){
1353 bool hadActiveFocus = hasActiveFocus();
1355 if (d->showInputPanelOnFocus) {
1356 if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1357 // re-open input panel on press if already focused
1358 openSoftwareInputPanel();
1360 } else { // show input panel on click
1361 if (hasActiveFocus() && !hadActiveFocus) {
1362 d->clickCausedFocus = true;
1367 d->control->processEvent(event, QPointF(0, -d->yoff));
1368 if (!event->isAccepted())
1369 QDeclarativePaintedItem::mousePressEvent(event);
1374 Handles the given mouse \a event.
1376 void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1378 Q_D(QDeclarativeTextEdit);
1379 d->control->processEvent(event, QPointF(0, -d->yoff));
1380 if (!d->showInputPanelOnFocus) { // input panel on click
1381 if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1382 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1383 if (view->scene() && view->scene() == scene()) {
1384 qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1389 d->clickCausedFocus = false;
1391 if (!event->isAccepted())
1392 QDeclarativePaintedItem::mouseReleaseEvent(event);
1397 Handles the given mouse \a event.
1399 void QDeclarativeTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1401 Q_D(QDeclarativeTextEdit);
1403 d->control->processEvent(event, QPointF(0, -d->yoff));
1404 if (!event->isAccepted())
1405 QDeclarativePaintedItem::mouseDoubleClickEvent(event);
1411 Handles the given mouse \a event.
1413 void QDeclarativeTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1415 Q_D(QDeclarativeTextEdit);
1416 d->control->processEvent(event, QPointF(0, -d->yoff));
1417 if (!event->isAccepted())
1418 QDeclarativePaintedItem::mouseMoveEvent(event);
1423 Handles the given input method \a event.
1425 void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event)
1427 Q_D(QDeclarativeTextEdit);
1428 const bool wasComposing = isInputMethodComposing();
1429 d->control->processEvent(event, QPointF(0, -d->yoff));
1430 if (wasComposing != isInputMethodComposing())
1431 emit inputMethodComposingChanged();
1436 Returns the value of the given \a property.
1438 QVariant QDeclarativeTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1440 Q_D(const QDeclarativeTextEdit);
1441 return d->control->inputMethodQuery(property);
1445 Draws the contents of the text edit using the given \a painter within
1446 the given \a bounds.
1448 void QDeclarativeTextEdit::drawContents(QPainter *painter, const QRect &bounds)
1450 Q_D(QDeclarativeTextEdit);
1452 painter->setRenderHint(QPainter::TextAntialiasing, true);
1453 painter->translate(0,d->yoff);
1455 d->control->drawContents(painter, bounds.translated(0,-d->yoff));
1457 painter->translate(0,-d->yoff);
1460 void QDeclarativeTextEdit::updateImgCache(const QRectF &rf)
1462 Q_D(const QDeclarativeTextEdit);
1464 if (!rf.isValid()) {
1465 r = QRect(0,0,INT_MAX,INT_MAX);
1468 if (r.height() > INT_MAX/2) {
1469 // Take care of overflow when translating "everything"
1470 r.setTop(r.y() + d->yoff);
1471 r.setBottom(INT_MAX/2);
1473 r = r.translated(0,d->yoff);
1481 \qmlproperty bool TextEdit::smooth
1483 This property holds whether the text is smoothly scaled or transformed.
1485 Smooth filtering gives better visual quality, but is slower. If
1486 the item is displayed at its natural size, this property has no visual or
1489 \note Generally scaling artifacts are only visible if the item is stationary on
1490 the screen. A common pattern when animating an item is to disable smooth
1491 filtering at the beginning of the animation and reenable it at the conclusion.
1495 \qmlproperty bool TextEdit::canPaste
1498 Returns true if the TextEdit is writable and the content of the clipboard is
1499 suitable for pasting into the TextEdit.
1501 bool QDeclarativeTextEdit::canPaste() const
1503 Q_D(const QDeclarativeTextEdit);
1508 \qmlproperty bool TextEdit::inputMethodComposing
1512 This property holds whether the TextEdit has partial text input from an
1515 While it is composing an input method may rely on mouse or key events from
1516 the TextEdit to edit or commit the partial text. This property can be used
1517 to determine when to disable events handlers that may interfere with the
1518 correct operation of an input method.
1520 bool QDeclarativeTextEdit::isInputMethodComposing() const
1522 Q_D(const QDeclarativeTextEdit);
1523 if (QTextLayout *layout = d->control->textCursor().block().layout())
1524 return layout->preeditAreaText().length() > 0;
1528 void QDeclarativeTextEditPrivate::init()
1530 Q_Q(QDeclarativeTextEdit);
1532 q->setSmooth(smooth);
1533 q->setAcceptedMouseButtons(Qt::LeftButton);
1534 q->setFlag(QGraphicsItem::ItemHasNoContents, false);
1535 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
1537 control = new QTextControl(q);
1538 control->setIgnoreUnusedNavigationEvents(true);
1539 control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1540 control->setDragEnabled(false);
1542 // QTextControl follows the default text color
1543 // defined by the platform, declarative text
1544 // should be black by default
1545 QPalette pal = control->palette();
1546 if (pal.color(QPalette::Text) != color) {
1547 pal.setColor(QPalette::Text, color);
1548 control->setPalette(pal);
1551 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF)));
1553 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1554 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1555 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1556 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1557 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1558 QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate()));
1559 QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1560 #ifndef QT_NO_CLIPBOARD
1561 QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged()));
1562 QObject::connect(QApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1563 canPaste = control->canPaste();
1566 document = control->document();
1567 document->setDefaultFont(font);
1568 document->setDocumentMargin(textMargin);
1569 document->setUndoRedoEnabled(false); // flush undo buffer.
1570 document->setUndoRedoEnabled(true);
1571 updateDefaultTextOption();
1574 void QDeclarativeTextEdit::q_textChanged()
1576 Q_D(QDeclarativeTextEdit);
1578 d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
1579 d->determineHorizontalAlignment();
1580 d->updateDefaultTextOption();
1583 emit textChanged(d->text);
1586 void QDeclarativeTextEdit::moveCursorDelegate()
1588 Q_D(QDeclarativeTextEdit);
1590 emit cursorRectangleChanged();
1593 QRectF cursorRect = cursorRectangle();
1594 d->cursor->setX(cursorRect.x());
1595 d->cursor->setY(cursorRect.y());
1598 void QDeclarativeTextEditPrivate::updateSelection()
1600 Q_Q(QDeclarativeTextEdit);
1601 QTextCursor cursor = control->textCursor();
1602 bool startChange = (lastSelectionStart != cursor.selectionStart());
1603 bool endChange = (lastSelectionEnd != cursor.selectionEnd());
1604 cursor.beginEditBlock();
1605 cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
1606 cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
1607 cursor.endEditBlock();
1608 control->setTextCursor(cursor);
1610 q->selectionStartChanged();
1612 q->selectionEndChanged();
1615 void QDeclarativeTextEdit::updateSelectionMarkers()
1617 Q_D(QDeclarativeTextEdit);
1618 if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
1619 d->lastSelectionStart = d->control->textCursor().selectionStart();
1620 emit selectionStartChanged();
1622 if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
1623 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1624 emit selectionEndChanged();
1628 QRectF QDeclarativeTextEdit::boundingRect() const
1630 Q_D(const QDeclarativeTextEdit);
1631 QRectF r = QDeclarativePaintedItem::boundingRect();
1632 int cursorWidth = 1;
1634 cursorWidth = d->cursor->width();
1635 if(!d->document->isEmpty())
1636 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1638 // Could include font max left/right bearings to either side of rectangle.
1640 r.setRight(r.right() + cursorWidth);
1641 return r.translated(0,d->yoff);
1644 qreal QDeclarativeTextEditPrivate::implicitWidth() const
1646 Q_Q(const QDeclarativeTextEdit);
1647 if (!requireImplicitWidth) {
1648 // We don't calculate implicitWidth unless it is required.
1649 // We need to force a size update now to ensure implicitWidth is calculated
1650 const_cast<QDeclarativeTextEditPrivate*>(this)->requireImplicitWidth = true;
1651 const_cast<QDeclarativeTextEdit*>(q)->updateSize();
1653 return mImplicitWidth;
1656 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1657 // need to do all the calculations each time
1658 void QDeclarativeTextEdit::updateSize()
1660 Q_D(QDeclarativeTextEdit);
1661 if (isComponentComplete()) {
1662 qreal naturalWidth = d->mImplicitWidth;
1663 // ### assumes that if the width is set, the text will fill to edges
1664 // ### (unless wrap is false, then clipping will occur)
1666 if (!d->requireImplicitWidth) {
1667 emit implicitWidthChanged();
1668 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1669 if (d->requireImplicitWidth)
1672 if (d->requireImplicitWidth) {
1673 d->document->setTextWidth(-1);
1674 naturalWidth = d->document->idealWidth();
1676 if (d->document->textWidth() != width())
1677 d->document->setTextWidth(width());
1679 d->document->setTextWidth(-1);
1681 QFontMetrics fm = QFontMetrics(d->font);
1683 dy -= (int)d->document->size().height();
1686 if (heightValid()) {
1687 if (d->vAlign == AlignBottom)
1689 else if (d->vAlign == AlignVCenter)
1696 if (nyoff != d->yoff) {
1697 prepareGeometryChange();
1700 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1702 //### need to comfirm cost of always setting these
1703 int newWidth = qCeil(d->document->idealWidth());
1704 if (!widthValid() && d->document->textWidth() != newWidth)
1705 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1706 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1708 setImplicitWidth(newWidth);
1709 else if (d->requireImplicitWidth)
1710 setImplicitWidth(naturalWidth);
1711 qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
1712 setImplicitHeight(newHeight);
1714 d->paintedSize = QSize(newWidth, newHeight);
1715 setContentsSize(d->paintedSize);
1716 emit paintedSizeChanged();
1723 void QDeclarativeTextEdit::updateTotalLines()
1725 Q_D(QDeclarativeTextEdit);
1729 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1730 QTextLayout *layout = it.layout();
1733 subLines += layout->lineCount()-1;
1736 int newTotalLines = d->document->lineCount() + subLines;
1737 if (d->lineCount != newTotalLines) {
1738 d->lineCount = newTotalLines;
1739 emit lineCountChanged();
1743 void QDeclarativeTextEditPrivate::updateDefaultTextOption()
1745 Q_Q(QDeclarativeTextEdit);
1746 QTextOption opt = document->defaultTextOption();
1747 int oldAlignment = opt.alignment();
1749 QDeclarativeTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
1750 if (rightToLeftText) {
1751 if (horizontalAlignment == QDeclarativeTextEdit::AlignLeft)
1752 horizontalAlignment = QDeclarativeTextEdit::AlignRight;
1753 else if (horizontalAlignment == QDeclarativeTextEdit::AlignRight)
1754 horizontalAlignment = QDeclarativeTextEdit::AlignLeft;
1756 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
1758 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1759 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
1761 if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
1763 document->setDefaultTextOption(opt);
1768 \qmlmethod void TextEdit::openSoftwareInputPanel()
1770 Opens software input panels like virtual keyboards for typing, useful for
1771 customizing when you want the input keyboard to be shown and hidden in
1774 By default the opening of input panels follows the platform style. On Symbian^1 and
1775 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1776 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1777 always closed if no editor has active focus.
1779 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1780 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1781 the behavior you want.
1783 Only relevant on platforms, which provide virtual keyboards.
1789 text: "Hello world!"
1790 activeFocusOnPress: false
1792 anchors.fill: parent
1794 if (!textEdit.activeFocus) {
1795 textEdit.forceActiveFocus();
1796 textEdit.openSoftwareInputPanel();
1798 textEdit.focus = false;
1801 onPressAndHold: textEdit.closeSoftwareInputPanel();
1806 void QDeclarativeTextEdit::openSoftwareInputPanel()
1808 QEvent event(QEvent::RequestSoftwareInputPanel);
1810 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1811 if (view->scene() && view->scene() == scene()) {
1812 QApplication::sendEvent(view, &event);
1819 \qmlmethod void TextEdit::closeSoftwareInputPanel()
1821 Closes a software input panel like a virtual keyboard shown on the screen, useful
1822 for customizing when you want the input keyboard to be shown and hidden in
1825 By default the opening of input panels follows the platform style. On Symbian^1 and
1826 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1827 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1828 always closed if no editor has active focus.
1830 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1831 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1832 the behavior you want.
1834 Only relevant on platforms, which provide virtual keyboards.
1840 text: "Hello world!"
1841 activeFocusOnPress: false
1843 anchors.fill: parent
1845 if (!textEdit.activeFocus) {
1846 textEdit.forceActiveFocus();
1847 textEdit.openSoftwareInputPanel();
1849 textEdit.focus = false;
1852 onPressAndHold: textEdit.closeSoftwareInputPanel();
1857 void QDeclarativeTextEdit::closeSoftwareInputPanel()
1859 QEvent event(QEvent::CloseSoftwareInputPanel);
1861 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1862 if (view->scene() && view->scene() == scene()) {
1863 QApplication::sendEvent(view, &event);
1869 void QDeclarativeTextEdit::focusInEvent(QFocusEvent *event)
1871 Q_D(const QDeclarativeTextEdit);
1872 if (d->showInputPanelOnFocus) {
1873 if (d->focusOnPress && !isReadOnly()) {
1874 openSoftwareInputPanel();
1877 QDeclarativePaintedItem::focusInEvent(event);
1880 void QDeclarativeTextEdit::q_canPasteChanged()
1882 Q_D(QDeclarativeTextEdit);
1883 bool old = d->canPaste;
1884 d->canPaste = d->control->canPaste();
1885 if(old!=d->canPaste)
1886 emit canPasteChanged();