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>
67 \qmlclass TextEdit QDeclarative1TextEdit
68 \inqmlmodule QtQuick 1
69 \ingroup qml-basic-visual-elements
71 \brief The TextEdit item displays multiple lines of editable formatted text.
74 The TextEdit item displays a block of editable, formatted text.
76 It can display both plain and rich text. For example:
81 text: "<b>Hello</b> <i>World!</i>"
82 font.family: "Helvetica"
89 \image declarative-textedit.gif
91 Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
93 Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
94 to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
96 \snippet snippets/declarative/texteditor.qml 0
98 A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible
99 scrollbar, or a scrollbar that fades in to show location, etc.
101 Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
102 be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
103 from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
105 You can translate between cursor positions (characters from the start of the document) and pixel
106 points using positionAt() and positionToRectangle().
108 \sa Text, TextInput, {declarative/text/textselection}{Text Selection example}
112 \qmlsignal QtQuick1::TextEdit::onLinkActivated(string link)
115 This handler is called when the user clicks on a link embedded in the text.
116 The link must be in rich text or HTML format and the
117 \a link string provides access to the particular link.
119 QDeclarative1TextEdit::QDeclarative1TextEdit(QDeclarativeItem *parent)
120 : QDeclarative1ImplicitSizePaintedItem(*(new QDeclarative1TextEditPrivate), parent)
122 Q_D(QDeclarative1TextEdit);
126 QString QDeclarative1TextEdit::text() const
128 Q_D(const QDeclarative1TextEdit);
130 #ifndef QT_NO_TEXTHTMLPARSER
132 return d->document->toHtml();
135 return d->document->toPlainText();
139 \qmlproperty string QtQuick1::TextEdit::font.family
141 Sets the family name of the font.
143 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
144 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
145 If the family isn't available a family will be set using the font matching algorithm.
149 \qmlproperty bool QtQuick1::TextEdit::font.bold
151 Sets whether the font weight is bold.
155 \qmlproperty enumeration QtQuick1::TextEdit::font.weight
157 Sets the font's weight.
159 The weight can be one of:
162 \o Font.Normal - the default
169 TextEdit { text: "Hello"; font.weight: Font.DemiBold }
174 \qmlproperty bool QtQuick1::TextEdit::font.italic
176 Sets whether the font has an italic style.
180 \qmlproperty bool QtQuick1::TextEdit::font.underline
182 Sets whether the text is underlined.
186 \qmlproperty bool QtQuick1::TextEdit::font.strikeout
188 Sets whether the font has a strikeout style.
192 \qmlproperty real QtQuick1::TextEdit::font.pointSize
194 Sets the font size in points. The point size must be greater than zero.
198 \qmlproperty int QtQuick1::TextEdit::font.pixelSize
200 Sets the font size in pixels.
202 Using this function makes the font device dependent. Use
203 \l{TextEdit::font.pointSize} to set the size of the font in a
204 device independent manner.
208 \qmlproperty real QtQuick1::TextEdit::font.letterSpacing
210 Sets the letter spacing for the font.
212 Letter spacing changes the default spacing between individual letters in the font.
213 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
217 \qmlproperty real QtQuick1::TextEdit::font.wordSpacing
219 Sets the word spacing for the font.
221 Word spacing changes the default spacing between individual words.
222 A positive value increases the word spacing by a corresponding amount of pixels,
223 while a negative value decreases the inter-word spacing accordingly.
227 \qmlproperty enumeration QtQuick1::TextEdit::font.capitalization
229 Sets the capitalization for the text.
232 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
233 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
234 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
235 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
236 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
240 TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
245 \qmlproperty string QtQuick1::TextEdit::text
247 The text to display. If the text format is AutoText the text edit will
248 automatically determine whether the text should be treated as
249 rich text. This determination is made using Qt::mightBeRichText().
251 void QDeclarative1TextEdit::setText(const QString &text)
253 Q_D(QDeclarative1TextEdit);
254 if (QDeclarative1TextEdit::text() == text)
257 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
259 #ifndef QT_NO_TEXTHTMLPARSER
260 d->control->setHtml(text);
262 d->control->setPlainText(text);
265 d->control->setPlainText(text);
271 \qmlproperty enumeration QtQuick1::TextEdit::textFormat
273 The way the text property should be displayed.
277 \o TextEdit.PlainText
281 The default is TextEdit.AutoText. If the text format is TextEdit.AutoText the text edit
282 will automatically determine whether the text should be treated as
283 rich text. This determination is made using Qt::mightBeRichText().
292 text: "<b>Hello</b> <i>World!</i>"
296 textFormat: TextEdit.RichText
297 text: "<b>Hello</b> <i>World!</i>"
301 textFormat: TextEdit.PlainText
302 text: "<b>Hello</b> <i>World!</i>"
306 \o \image declarative-textformat.png
309 QDeclarative1TextEdit::TextFormat QDeclarative1TextEdit::textFormat() const
311 Q_D(const QDeclarative1TextEdit);
315 void QDeclarative1TextEdit::setTextFormat(TextFormat format)
317 Q_D(QDeclarative1TextEdit);
318 if (format == d->format)
320 bool wasRich = d->richText;
321 d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
323 if (wasRich && !d->richText) {
324 d->control->setPlainText(d->text);
326 } else if (!wasRich && d->richText) {
327 #ifndef QT_NO_TEXTHTMLPARSER
328 d->control->setHtml(d->text);
330 d->control->setPlainText(d->text);
335 d->control->setAcceptRichText(d->format != PlainText);
336 emit textFormatChanged(d->format);
339 QFont QDeclarative1TextEdit::font() const
341 Q_D(const QDeclarative1TextEdit);
342 return d->sourceFont;
345 void QDeclarative1TextEdit::setFont(const QFont &font)
347 Q_D(QDeclarative1TextEdit);
348 if (d->sourceFont == font)
351 d->sourceFont = font;
352 QFont oldFont = d->font;
354 if (d->font.pointSizeF() != -1) {
356 qreal size = qRound(d->font.pointSizeF()*2.0);
357 d->font.setPointSizeF(size/2.0);
360 if (oldFont != d->font) {
362 d->document->setDefaultFont(d->font);
364 d->cursor->setHeight(QFontMetrics(d->font).height());
365 moveCursorDelegate();
370 emit fontChanged(d->sourceFont);
374 \qmlproperty color QtQuick1::TextEdit::color
379 // green text using hexadecimal notation
380 TextEdit { color: "#00FF00" }
384 // steelblue text using SVG color name
385 TextEdit { color: "steelblue" }
388 QColor QDeclarative1TextEdit::color() const
390 Q_D(const QDeclarative1TextEdit);
394 void QDeclarative1TextEdit::setColor(const QColor &color)
396 Q_D(QDeclarative1TextEdit);
397 if (d->color == color)
402 QPalette pal = d->control->palette();
403 pal.setColor(QPalette::Text, color);
404 d->control->setPalette(pal);
406 emit colorChanged(d->color);
410 \qmlproperty color QtQuick1::TextEdit::selectionColor
412 The text highlight color, used behind selections.
414 QColor QDeclarative1TextEdit::selectionColor() const
416 Q_D(const QDeclarative1TextEdit);
417 return d->selectionColor;
420 void QDeclarative1TextEdit::setSelectionColor(const QColor &color)
422 Q_D(QDeclarative1TextEdit);
423 if (d->selectionColor == color)
427 d->selectionColor = color;
428 QPalette pal = d->control->palette();
429 pal.setColor(QPalette::Highlight, color);
430 d->control->setPalette(pal);
432 emit selectionColorChanged(d->selectionColor);
436 \qmlproperty color QtQuick1::TextEdit::selectedTextColor
438 The selected text color, used in selections.
440 QColor QDeclarative1TextEdit::selectedTextColor() const
442 Q_D(const QDeclarative1TextEdit);
443 return d->selectedTextColor;
446 void QDeclarative1TextEdit::setSelectedTextColor(const QColor &color)
448 Q_D(QDeclarative1TextEdit);
449 if (d->selectedTextColor == color)
453 d->selectedTextColor = color;
454 QPalette pal = d->control->palette();
455 pal.setColor(QPalette::HighlightedText, color);
456 d->control->setPalette(pal);
458 emit selectedTextColorChanged(d->selectedTextColor);
462 \qmlproperty enumeration QtQuick1::TextEdit::horizontalAlignment
463 \qmlproperty enumeration QtQuick1::TextEdit::verticalAlignment
464 \qmlproperty enumeration QtQuick1::TextEdit::effectiveHorizontalAlignment
466 Sets the horizontal and vertical alignment of the text within the TextEdit item's
467 width and height. By default, the text alignment follows the natural alignment
468 of the text, for example text that is read from left to right will be aligned to
471 Valid values for \c horizontalAlignment are:
473 \o TextEdit.AlignLeft (default)
474 \o TextEdit.AlignRight
475 \o TextEdit.AlignHCenter
476 \o TextEdit.AlignJustify
479 Valid values for \c verticalAlignment are:
481 \o TextEdit.AlignTop (default)
482 \o TextEdit.AlignBottom
483 \o TextEdit.AlignVCenter
486 When using the attached property LayoutMirroring::enabled to mirror application
487 layouts, the horizontal alignment of text will also be mirrored. However, the property
488 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
489 of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
491 QDeclarative1TextEdit::HAlignment QDeclarative1TextEdit::hAlign() const
493 Q_D(const QDeclarative1TextEdit);
497 void QDeclarative1TextEdit::setHAlign(HAlignment align)
499 Q_D(QDeclarative1TextEdit);
500 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
501 d->hAlignImplicit = false;
502 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
503 d->updateDefaultTextOption();
508 void QDeclarative1TextEdit::resetHAlign()
510 Q_D(QDeclarative1TextEdit);
511 d->hAlignImplicit = true;
512 if (d->determineHorizontalAlignment() && isComponentComplete()) {
513 d->updateDefaultTextOption();
518 QDeclarative1TextEdit::HAlignment QDeclarative1TextEdit::effectiveHAlign() const
520 Q_D(const QDeclarative1TextEdit);
521 QDeclarative1TextEdit::HAlignment effectiveAlignment = d->hAlign;
522 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
524 case QDeclarative1TextEdit::AlignLeft:
525 effectiveAlignment = QDeclarative1TextEdit::AlignRight;
527 case QDeclarative1TextEdit::AlignRight:
528 effectiveAlignment = QDeclarative1TextEdit::AlignLeft;
534 return effectiveAlignment;
537 bool QDeclarative1TextEditPrivate::setHAlign(QDeclarative1TextEdit::HAlignment alignment, bool forceAlign)
539 Q_Q(QDeclarative1TextEdit);
540 if (hAlign != alignment || forceAlign) {
541 QDeclarative1TextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
543 emit q->horizontalAlignmentChanged(alignment);
544 if (oldEffectiveHAlign != q->effectiveHAlign())
545 emit q->effectiveHorizontalAlignmentChanged();
551 bool QDeclarative1TextEditPrivate::determineHorizontalAlignment()
553 Q_Q(QDeclarative1TextEdit);
554 if (hAlignImplicit && q->isComponentComplete()) {
555 bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
556 return setHAlign(alignToRight ? QDeclarative1TextEdit::AlignRight : QDeclarative1TextEdit::AlignLeft);
561 void QDeclarative1TextEditPrivate::mirrorChange()
563 Q_Q(QDeclarative1TextEdit);
564 if (q->isComponentComplete()) {
565 if (!hAlignImplicit && (hAlign == QDeclarative1TextEdit::AlignRight || hAlign == QDeclarative1TextEdit::AlignLeft)) {
566 updateDefaultTextOption();
568 emit q->effectiveHorizontalAlignmentChanged();
573 QDeclarative1TextEdit::VAlignment QDeclarative1TextEdit::vAlign() const
575 Q_D(const QDeclarative1TextEdit);
579 void QDeclarative1TextEdit::setVAlign(QDeclarative1TextEdit::VAlignment alignment)
581 Q_D(QDeclarative1TextEdit);
582 if (alignment == d->vAlign)
584 d->vAlign = alignment;
585 d->updateDefaultTextOption();
587 moveCursorDelegate();
588 emit verticalAlignmentChanged(d->vAlign);
592 \qmlproperty enumeration QtQuick1::TextEdit::wrapMode
594 Set this property to wrap the text to the TextEdit item's width.
595 The text will only wrap if an explicit width has been set.
598 \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
599 \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
600 \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
601 \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.
604 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
606 QDeclarative1TextEdit::WrapMode QDeclarative1TextEdit::wrapMode() const
608 Q_D(const QDeclarative1TextEdit);
612 void QDeclarative1TextEdit::setWrapMode(WrapMode mode)
614 Q_D(QDeclarative1TextEdit);
615 if (mode == d->wrapMode)
618 d->updateDefaultTextOption();
620 emit wrapModeChanged();
624 \qmlproperty int QtQuick1::TextEdit::lineCount
627 Returns the total number of lines in the textEdit item.
629 int QDeclarative1TextEdit::lineCount() const
631 Q_D(const QDeclarative1TextEdit);
636 \qmlproperty real QtQuick1::TextEdit::paintedWidth
638 Returns the width of the text, including the width past the width
639 which is covered due to insufficient wrapping if \l wrapMode is set.
641 qreal QDeclarative1TextEdit::paintedWidth() const
643 Q_D(const QDeclarative1TextEdit);
644 return d->paintedSize.width();
648 \qmlproperty real QtQuick1::TextEdit::paintedHeight
650 Returns the height of the text, including the height past the height
651 that is covered if the text does not fit within the set height.
653 qreal QDeclarative1TextEdit::paintedHeight() const
655 Q_D(const QDeclarative1TextEdit);
656 return d->paintedSize.height();
660 \qmlmethod rectangle QtQuick1::TextEdit::positionToRectangle(position)
662 Returns the rectangle at the given \a position in the text. The x, y,
663 and height properties correspond to the cursor that would describe
666 QRectF QDeclarative1TextEdit::positionToRectangle(int pos) const
668 Q_D(const QDeclarative1TextEdit);
669 QTextCursor c(d->document);
671 return d->control->cursorRect(c);
676 \qmlmethod int QtQuick1::TextEdit::positionAt(int x, int y)
678 Returns the text position closest to pixel position (\a x, \a y).
680 Position 0 is before the first character, position 1 is after the first character
681 but before the second, and so on until position \l {text}.length, which is after all characters.
683 int QDeclarative1TextEdit::positionAt(int x, int y) const
685 Q_D(const QDeclarative1TextEdit);
686 int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
687 QTextCursor cursor = d->control->textCursor();
688 if (r > cursor.position()) {
689 // The cursor position includes positions within the preedit text, but only positions in the
690 // same text block are offset so it is possible to get a position that is either part of the
691 // preedit or the next text block.
692 QTextLayout *layout = cursor.block().layout();
693 const int preeditLength = layout
694 ? layout->preeditAreaText().length()
696 if (preeditLength > 0
697 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
698 r = r > cursor.position() + preeditLength
706 void QDeclarative1TextEdit::moveCursorSelection(int pos)
708 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
709 Q_D(QDeclarative1TextEdit);
710 QTextCursor cursor = d->control->textCursor();
711 if (cursor.position() == pos)
713 cursor.setPosition(pos, QTextCursor::KeepAnchor);
714 d->control->setTextCursor(cursor);
718 \qmlmethod void QtQuick1::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
721 Moves the cursor to \a position and updates the selection according to the optional \a mode
722 parameter. (To only move the cursor, set the \l cursorPosition property.)
724 When this method is called it additionally sets either the
725 selectionStart or the selectionEnd (whichever was at the previous cursor position)
726 to the specified position. This allows you to easily extend and contract the selected
729 The selection mode specifies whether the selection is updated on a per character or a per word
730 basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
733 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
734 the previous cursor position) to the specified position.
735 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
736 words between the specified postion and the previous cursor position. Words partially in the
740 For example, take this sequence of calls:
744 moveCursorSelection(9, TextEdit.SelectCharacters)
745 moveCursorSelection(7, TextEdit.SelectCharacters)
748 This moves the cursor to position 5, extend the selection end from 5 to 9
749 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
750 selected (the 6th and 7th characters).
752 The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
753 before or on position 5 and extend the selection end to a word boundary on or past position 9.
755 void QDeclarative1TextEdit::moveCursorSelection(int pos, SelectionMode mode)
757 Q_D(QDeclarative1TextEdit);
758 QTextCursor cursor = d->control->textCursor();
759 if (cursor.position() == pos)
761 if (mode == SelectCharacters) {
762 cursor.setPosition(pos, QTextCursor::KeepAnchor);
763 } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
764 if (cursor.anchor() > cursor.position()) {
765 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
766 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
767 if (cursor.position() == cursor.anchor())
768 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
770 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
772 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
773 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
776 cursor.setPosition(pos, QTextCursor::KeepAnchor);
777 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
778 if (cursor.position() != pos)
779 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
780 } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
781 if (cursor.anchor() < cursor.position()) {
782 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
783 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
785 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
786 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
787 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
788 if (cursor.position() != cursor.anchor()) {
789 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
790 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
794 cursor.setPosition(pos, QTextCursor::KeepAnchor);
795 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
796 if (cursor.position() != pos) {
797 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
798 cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
801 d->control->setTextCursor(cursor);
805 \qmlproperty bool QtQuick1::TextEdit::cursorVisible
806 If true the text edit shows a cursor.
808 This property is set and unset when the text edit gets active focus, but it can also
809 be set directly (useful, for example, if a KeyProxy might forward keys to it).
811 bool QDeclarative1TextEdit::isCursorVisible() const
813 Q_D(const QDeclarative1TextEdit);
814 return d->cursorVisible;
817 void QDeclarative1TextEdit::setCursorVisible(bool on)
819 Q_D(QDeclarative1TextEdit);
820 if (d->cursorVisible == on)
822 d->cursorVisible = on;
823 QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
824 if (!on && !d->persistentSelection)
825 d->control->setCursorIsFocusIndicator(true);
826 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
827 emit cursorVisibleChanged(d->cursorVisible);
831 \qmlproperty int QtQuick1::TextEdit::cursorPosition
832 The position of the cursor in the TextEdit.
834 int QDeclarative1TextEdit::cursorPosition() const
836 Q_D(const QDeclarative1TextEdit);
837 return d->control->textCursor().position();
840 void QDeclarative1TextEdit::setCursorPosition(int pos)
842 Q_D(QDeclarative1TextEdit);
843 if (pos < 0 || pos > d->text.length())
845 QTextCursor cursor = d->control->textCursor();
846 if (cursor.position() == pos && cursor.anchor() == pos)
848 cursor.setPosition(pos);
849 d->control->setTextCursor(cursor);
853 \qmlproperty Component QtQuick1::TextEdit::cursorDelegate
854 The delegate for the cursor in the TextEdit.
856 If you set a cursorDelegate for a TextEdit, this delegate will be used for
857 drawing the cursor instead of the standard cursor. An instance of the
858 delegate will be created and managed by the text edit when a cursor is
859 needed, and the x and y properties of delegate instance will be set so as
860 to be one pixel before the top left of the current character.
862 Note that the root item of the delegate component must be a QDeclarativeItem or
863 QDeclarativeItem derived item.
865 QDeclarativeComponent* QDeclarative1TextEdit::cursorDelegate() const
867 Q_D(const QDeclarative1TextEdit);
868 return d->cursorComponent;
871 void QDeclarative1TextEdit::setCursorDelegate(QDeclarativeComponent* c)
873 Q_D(QDeclarative1TextEdit);
874 if(d->cursorComponent){
876 d->control->setCursorWidth(-1);
877 dirtyCache(cursorRectangle());
882 d->cursorComponent = c;
883 if(c && c->isReady()){
884 loadCursorDelegate();
887 connect(c, SIGNAL(statusChanged()),
888 this, SLOT(loadCursorDelegate()));
891 emit cursorDelegateChanged();
894 void QDeclarative1TextEdit::loadCursorDelegate()
896 Q_D(QDeclarative1TextEdit);
897 if(d->cursorComponent->isLoading())
899 d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this)));
901 d->control->setCursorWidth(0);
902 dirtyCache(cursorRectangle());
903 QDeclarative_setParent_noEvent(d->cursor, this);
904 d->cursor->setParentItem(this);
905 d->cursor->setHeight(QFontMetrics(d->font).height());
906 moveCursorDelegate();
908 qmlInfo(this) << "Error loading cursor delegate.";
913 \qmlproperty int QtQuick1::TextEdit::selectionStart
915 The cursor position before the first character in the current selection.
917 This property is read-only. To change the selection, use select(start,end),
918 selectAll(), or selectWord().
920 \sa selectionEnd, cursorPosition, selectedText
922 int QDeclarative1TextEdit::selectionStart() const
924 Q_D(const QDeclarative1TextEdit);
925 return d->control->textCursor().selectionStart();
929 \qmlproperty int QtQuick1::TextEdit::selectionEnd
931 The cursor position after the last character in the current selection.
933 This property is read-only. To change the selection, use select(start,end),
934 selectAll(), or selectWord().
936 \sa selectionStart, cursorPosition, selectedText
938 int QDeclarative1TextEdit::selectionEnd() const
940 Q_D(const QDeclarative1TextEdit);
941 return d->control->textCursor().selectionEnd();
945 \qmlproperty string QtQuick1::TextEdit::selectedText
947 This read-only property provides the text currently selected in the
950 It is equivalent to the following snippet, but is faster and easier
953 //myTextEdit is the id of the TextEdit
954 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
955 myTextEdit.selectionEnd);
958 QString QDeclarative1TextEdit::selectedText() const
960 Q_D(const QDeclarative1TextEdit);
961 return d->control->textCursor().selectedText();
965 \qmlproperty bool QtQuick1::TextEdit::activeFocusOnPress
967 Whether the TextEdit should gain active focus on a mouse press. By default this is
970 bool QDeclarative1TextEdit::focusOnPress() const
972 Q_D(const QDeclarative1TextEdit);
973 return d->focusOnPress;
976 void QDeclarative1TextEdit::setFocusOnPress(bool on)
978 Q_D(QDeclarative1TextEdit);
979 if (d->focusOnPress == on)
981 d->focusOnPress = on;
982 emit activeFocusOnPressChanged(d->focusOnPress);
986 \qmlproperty bool QtQuick1::TextEdit::persistentSelection
988 Whether the TextEdit should keep the selection visible when it loses active focus to another
989 item in the scene. By default this is set to true;
991 bool QDeclarative1TextEdit::persistentSelection() const
993 Q_D(const QDeclarative1TextEdit);
994 return d->persistentSelection;
997 void QDeclarative1TextEdit::setPersistentSelection(bool on)
999 Q_D(QDeclarative1TextEdit);
1000 if (d->persistentSelection == on)
1002 d->persistentSelection = on;
1003 emit persistentSelectionChanged(d->persistentSelection);
1007 \qmlproperty real QtQuick1::TextEdit::textMargin
1009 The margin, in pixels, around the text in the TextEdit.
1011 qreal QDeclarative1TextEdit::textMargin() const
1013 Q_D(const QDeclarative1TextEdit);
1014 return d->textMargin;
1017 void QDeclarative1TextEdit::setTextMargin(qreal margin)
1019 Q_D(QDeclarative1TextEdit);
1020 if (d->textMargin == margin)
1022 d->textMargin = margin;
1023 d->document->setDocumentMargin(d->textMargin);
1024 emit textMarginChanged(d->textMargin);
1027 void QDeclarative1TextEdit::geometryChanged(const QRectF &newGeometry,
1028 const QRectF &oldGeometry)
1030 if (newGeometry.width() != oldGeometry.width())
1032 QDeclarative1PaintedItem::geometryChanged(newGeometry, oldGeometry);
1036 Ensures any delayed caching or data loading the class
1037 needs to performed is complete.
1039 void QDeclarative1TextEdit::componentComplete()
1041 Q_D(QDeclarative1TextEdit);
1042 QDeclarative1PaintedItem::componentComplete();
1044 d->determineHorizontalAlignment();
1045 d->updateDefaultTextOption();
1052 \qmlproperty bool QtQuick1::TextEdit::selectByMouse
1056 If true, the user can use the mouse to select text in some
1057 platform-specific way. Note that for some platforms this may
1058 not be an appropriate interaction (eg. may conflict with how
1059 the text needs to behave inside a Flickable.
1061 bool QDeclarative1TextEdit::selectByMouse() const
1063 Q_D(const QDeclarative1TextEdit);
1064 return d->selectByMouse;
1067 void QDeclarative1TextEdit::setSelectByMouse(bool on)
1069 Q_D(QDeclarative1TextEdit);
1070 if (d->selectByMouse != on) {
1071 d->selectByMouse = on;
1072 setKeepMouseGrab(on);
1074 setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1076 setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1077 emit selectByMouseChanged(on);
1083 \qmlproperty enum QtQuick1::TextEdit::mouseSelectionMode
1086 Specifies how text should be selected using a mouse.
1089 \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1090 \o TextEdit.SelectWords - The selection is updated with whole words.
1093 This property only applies when \l selectByMouse is true.
1096 QDeclarative1TextEdit::SelectionMode QDeclarative1TextEdit::mouseSelectionMode() const
1098 Q_D(const QDeclarative1TextEdit);
1099 return d->mouseSelectionMode;
1102 void QDeclarative1TextEdit::setMouseSelectionMode(SelectionMode mode)
1104 Q_D(QDeclarative1TextEdit);
1105 if (d->mouseSelectionMode != mode) {
1106 d->mouseSelectionMode = mode;
1107 d->control->setWordSelectionEnabled(mode == SelectWords);
1108 emit mouseSelectionModeChanged(mode);
1113 \qmlproperty bool QtQuick1::TextEdit::readOnly
1115 Whether the user can interact with the TextEdit item. If this
1116 property is set to true the text cannot be edited by user interaction.
1118 By default this property is false.
1120 void QDeclarative1TextEdit::setReadOnly(bool r)
1122 Q_D(QDeclarative1TextEdit);
1123 if (r == isReadOnly())
1126 setFlag(QGraphicsItem::ItemAcceptsInputMethod, !r);
1128 Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1129 if (d->selectByMouse)
1130 flags = flags | Qt::TextSelectableByMouse;
1132 flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1133 d->control->setTextInteractionFlags(flags);
1135 d->control->moveCursor(QTextCursor::End);
1137 emit readOnlyChanged(r);
1140 bool QDeclarative1TextEdit::isReadOnly() const
1142 Q_D(const QDeclarative1TextEdit);
1143 return !(d->control->textInteractionFlags() & Qt::TextEditable);
1147 Sets how the text edit should interact with user input to the given
1150 void QDeclarative1TextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1152 Q_D(QDeclarative1TextEdit);
1153 d->control->setTextInteractionFlags(flags);
1157 Returns the flags specifying how the text edit should interact
1160 Qt::TextInteractionFlags QDeclarative1TextEdit::textInteractionFlags() const
1162 Q_D(const QDeclarative1TextEdit);
1163 return d->control->textInteractionFlags();
1167 \qmlproperty rectangle QtQuick1::TextEdit::cursorRectangle
1169 The rectangle where the text cursor is rendered
1170 within the text edit. Read-only.
1172 QRect QDeclarative1TextEdit::cursorRectangle() const
1174 Q_D(const QDeclarative1TextEdit);
1175 return d->control->cursorRect().toRect().translated(0,d->yoff);
1181 Handles the given \a event.
1183 bool QDeclarative1TextEdit::event(QEvent *event)
1185 Q_D(QDeclarative1TextEdit);
1186 if (event->type() == QEvent::ShortcutOverride) {
1187 d->control->processEvent(event, QPointF(0, -d->yoff));
1188 return event->isAccepted();
1190 return QDeclarative1PaintedItem::event(event);
1195 Handles the given key \a event.
1197 void QDeclarative1TextEdit::keyPressEvent(QKeyEvent *event)
1199 Q_D(QDeclarative1TextEdit);
1200 keyPressPreHandler(event);
1201 if (!event->isAccepted())
1202 d->control->processEvent(event, QPointF(0, -d->yoff));
1203 if (!event->isAccepted())
1204 QDeclarative1PaintedItem::keyPressEvent(event);
1209 Handles the given key \a event.
1211 void QDeclarative1TextEdit::keyReleaseEvent(QKeyEvent *event)
1213 Q_D(QDeclarative1TextEdit);
1214 keyReleasePreHandler(event);
1215 if (!event->isAccepted())
1216 d->control->processEvent(event, QPointF(0, -d->yoff));
1217 if (!event->isAccepted())
1218 QDeclarative1PaintedItem::keyReleaseEvent(event);
1221 void QDeclarative1TextEditPrivate::focusChanged(bool hasFocus)
1223 Q_Q(QDeclarative1TextEdit);
1224 q->setCursorVisible(hasFocus && scene && scene->hasFocus());
1225 QDeclarativeItemPrivate::focusChanged(hasFocus);
1229 \qmlmethod void QtQuick1::TextEdit::deselect()
1232 Removes active text selection.
1234 void QDeclarative1TextEdit::deselect()
1236 Q_D(QDeclarative1TextEdit);
1237 QTextCursor c = d->control->textCursor();
1239 d->control->setTextCursor(c);
1243 \qmlmethod void QtQuick1::TextEdit::selectAll()
1245 Causes all text to be selected.
1247 void QDeclarative1TextEdit::selectAll()
1249 Q_D(QDeclarative1TextEdit);
1250 d->control->selectAll();
1254 \qmlmethod void QtQuick1::TextEdit::selectWord()
1256 Causes the word closest to the current cursor position to be selected.
1258 void QDeclarative1TextEdit::selectWord()
1260 Q_D(QDeclarative1TextEdit);
1261 QTextCursor c = d->control->textCursor();
1262 c.select(QTextCursor::WordUnderCursor);
1263 d->control->setTextCursor(c);
1267 \qmlmethod void QtQuick1::TextEdit::select(int start, int end)
1269 Causes the text from \a start to \a end to be selected.
1271 If either start or end is out of range, the selection is not changed.
1273 After calling this, selectionStart will become the lesser
1274 and selectionEnd will become the greater (regardless of the order passed
1277 \sa selectionStart, selectionEnd
1279 void QDeclarative1TextEdit::select(int start, int end)
1281 Q_D(QDeclarative1TextEdit);
1282 if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
1284 QTextCursor cursor = d->control->textCursor();
1285 cursor.beginEditBlock();
1286 cursor.setPosition(start, QTextCursor::MoveAnchor);
1287 cursor.setPosition(end, QTextCursor::KeepAnchor);
1288 cursor.endEditBlock();
1289 d->control->setTextCursor(cursor);
1292 updateSelectionMarkers();
1296 \qmlmethod void QtQuick1::TextEdit::isRightToLeft(int start, int end)
1298 Returns true if the natural reading direction of the editor text
1299 found between positions \a start and \a end is right to left.
1301 bool QDeclarative1TextEdit::isRightToLeft(int start, int end)
1303 Q_D(QDeclarative1TextEdit);
1305 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1308 return d->text.mid(start, end - start).isRightToLeft();
1312 #ifndef QT_NO_CLIPBOARD
1314 \qmlmethod QtQuick1::TextEdit::cut()
1316 Moves the currently selected text to the system clipboard.
1318 void QDeclarative1TextEdit::cut()
1320 Q_D(QDeclarative1TextEdit);
1325 \qmlmethod QtQuick1::TextEdit::copy()
1327 Copies the currently selected text to the system clipboard.
1329 void QDeclarative1TextEdit::copy()
1331 Q_D(QDeclarative1TextEdit);
1336 \qmlmethod QtQuick1::TextEdit::paste()
1338 Replaces the currently selected text by the contents of the system clipboard.
1340 void QDeclarative1TextEdit::paste()
1342 Q_D(QDeclarative1TextEdit);
1343 d->control->paste();
1345 #endif // QT_NO_CLIPBOARD
1349 Handles the given mouse \a event.
1351 void QDeclarative1TextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
1353 Q_D(QDeclarative1TextEdit);
1354 if (d->focusOnPress){
1355 bool hadActiveFocus = hasActiveFocus();
1357 if (d->showInputPanelOnFocus) {
1358 if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1359 // re-open input panel on press if already focused
1360 openSoftwareInputPanel();
1362 } else { // show input panel on click
1363 if (hasActiveFocus() && !hadActiveFocus) {
1364 d->clickCausedFocus = true;
1369 d->control->processEvent(event, QPointF(0, -d->yoff));
1370 if (!event->isAccepted())
1371 QDeclarative1PaintedItem::mousePressEvent(event);
1376 Handles the given mouse \a event.
1378 void QDeclarative1TextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1380 Q_D(QDeclarative1TextEdit);
1381 d->control->processEvent(event, QPointF(0, -d->yoff));
1382 if (!d->showInputPanelOnFocus) { // input panel on click
1383 if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1384 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1385 if (view->scene() && view->scene() == scene()) {
1386 qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1391 d->clickCausedFocus = false;
1393 if (!event->isAccepted())
1394 QDeclarative1PaintedItem::mouseReleaseEvent(event);
1399 Handles the given mouse \a event.
1401 void QDeclarative1TextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1403 Q_D(QDeclarative1TextEdit);
1405 d->control->processEvent(event, QPointF(0, -d->yoff));
1406 if (!event->isAccepted())
1407 QDeclarative1PaintedItem::mouseDoubleClickEvent(event);
1413 Handles the given mouse \a event.
1415 void QDeclarative1TextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1417 Q_D(QDeclarative1TextEdit);
1418 d->control->processEvent(event, QPointF(0, -d->yoff));
1419 if (!event->isAccepted())
1420 QDeclarative1PaintedItem::mouseMoveEvent(event);
1425 Handles the given input method \a event.
1427 void QDeclarative1TextEdit::inputMethodEvent(QInputMethodEvent *event)
1429 Q_D(QDeclarative1TextEdit);
1430 const bool wasComposing = isInputMethodComposing();
1431 d->control->processEvent(event, QPointF(0, -d->yoff));
1432 if (wasComposing != isInputMethodComposing())
1433 emit inputMethodComposingChanged();
1438 Returns the value of the given \a property.
1440 QVariant QDeclarative1TextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1442 Q_D(const QDeclarative1TextEdit);
1443 return d->control->inputMethodQuery(property);
1447 Draws the contents of the text edit using the given \a painter within
1448 the given \a bounds.
1450 void QDeclarative1TextEdit::drawContents(QPainter *painter, const QRect &bounds)
1452 Q_D(QDeclarative1TextEdit);
1454 painter->setRenderHint(QPainter::TextAntialiasing, true);
1455 painter->translate(0,d->yoff);
1457 d->control->drawContents(painter, bounds.translated(0,-d->yoff));
1459 painter->translate(0,-d->yoff);
1462 void QDeclarative1TextEdit::updateImgCache(const QRectF &rf)
1464 Q_D(const QDeclarative1TextEdit);
1466 if (!rf.isValid()) {
1467 r = QRect(0,0,INT_MAX,INT_MAX);
1470 if (r.height() > INT_MAX/2) {
1471 // Take care of overflow when translating "everything"
1472 r.setTop(r.y() + d->yoff);
1473 r.setBottom(INT_MAX/2);
1475 r = r.translated(0,d->yoff);
1483 \qmlproperty bool QtQuick1::TextEdit::smooth
1485 This property holds whether the text is smoothly scaled or transformed.
1487 Smooth filtering gives better visual quality, but is slower. If
1488 the item is displayed at its natural size, this property has no visual or
1491 \note Generally scaling artifacts are only visible if the item is stationary on
1492 the screen. A common pattern when animating an item is to disable smooth
1493 filtering at the beginning of the animation and reenable it at the conclusion.
1497 \qmlproperty bool QtQuick1::TextEdit::canPaste
1500 Returns true if the TextEdit is writable and the content of the clipboard is
1501 suitable for pasting into the TextEdit.
1503 bool QDeclarative1TextEdit::canPaste() const
1505 Q_D(const QDeclarative1TextEdit);
1510 \qmlproperty bool QtQuick1::TextEdit::inputMethodComposing
1514 This property holds whether the TextEdit has partial text input from an
1517 While it is composing an input method may rely on mouse or key events from
1518 the TextEdit to edit or commit the partial text. This property can be used
1519 to determine when to disable events handlers that may interfere with the
1520 correct operation of an input method.
1522 bool QDeclarative1TextEdit::isInputMethodComposing() const
1524 Q_D(const QDeclarative1TextEdit);
1525 if (QTextLayout *layout = d->control->textCursor().block().layout())
1526 return layout->preeditAreaText().length() > 0;
1530 void QDeclarative1TextEditPrivate::init()
1532 Q_Q(QDeclarative1TextEdit);
1534 q->setSmooth(smooth);
1535 q->setAcceptedMouseButtons(Qt::LeftButton);
1536 q->setFlag(QGraphicsItem::ItemHasNoContents, false);
1537 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
1539 control = new QTextControl(q);
1540 control->setIgnoreUnusedNavigationEvents(true);
1541 control->setTextInteractionFlags(Qt::TextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable));
1542 control->setDragEnabled(false);
1544 // QTextControl follows the default text color
1545 // defined by the platform, declarative text
1546 // should be black by default
1547 QPalette pal = control->palette();
1548 if (pal.color(QPalette::Text) != color) {
1549 pal.setColor(QPalette::Text, color);
1550 control->setPalette(pal);
1553 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF)));
1555 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1556 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1557 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1558 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1559 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1560 QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate()));
1561 QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1562 #ifndef QT_NO_CLIPBOARD
1563 QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged()));
1564 QObject::connect(QApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1565 canPaste = control->canPaste();
1568 document = control->document();
1569 document->setDefaultFont(font);
1570 document->setDocumentMargin(textMargin);
1571 document->setUndoRedoEnabled(false); // flush undo buffer.
1572 document->setUndoRedoEnabled(true);
1573 updateDefaultTextOption();
1576 void QDeclarative1TextEdit::q_textChanged()
1578 Q_D(QDeclarative1TextEdit);
1580 d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
1581 d->determineHorizontalAlignment();
1582 d->updateDefaultTextOption();
1585 emit textChanged(d->text);
1588 void QDeclarative1TextEdit::moveCursorDelegate()
1590 Q_D(QDeclarative1TextEdit);
1592 emit cursorRectangleChanged();
1595 QRectF cursorRect = cursorRectangle();
1596 d->cursor->setX(cursorRect.x());
1597 d->cursor->setY(cursorRect.y());
1600 void QDeclarative1TextEditPrivate::updateSelection()
1602 Q_Q(QDeclarative1TextEdit);
1603 QTextCursor cursor = control->textCursor();
1604 bool startChange = (lastSelectionStart != cursor.selectionStart());
1605 bool endChange = (lastSelectionEnd != cursor.selectionEnd());
1606 cursor.beginEditBlock();
1607 cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
1608 cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
1609 cursor.endEditBlock();
1610 control->setTextCursor(cursor);
1612 q->selectionStartChanged();
1614 q->selectionEndChanged();
1617 void QDeclarative1TextEdit::updateSelectionMarkers()
1619 Q_D(QDeclarative1TextEdit);
1620 if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
1621 d->lastSelectionStart = d->control->textCursor().selectionStart();
1622 emit selectionStartChanged();
1624 if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
1625 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1626 emit selectionEndChanged();
1630 QRectF QDeclarative1TextEdit::boundingRect() const
1632 Q_D(const QDeclarative1TextEdit);
1633 QRectF r = QDeclarative1PaintedItem::boundingRect();
1634 int cursorWidth = 1;
1636 cursorWidth = d->cursor->width();
1637 if(!d->document->isEmpty())
1638 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1640 // Could include font max left/right bearings to either side of rectangle.
1642 r.setRight(r.right() + cursorWidth);
1643 return r.translated(0,d->yoff);
1646 qreal QDeclarative1TextEditPrivate::implicitWidth() const
1648 Q_Q(const QDeclarative1TextEdit);
1649 if (!requireImplicitWidth) {
1650 // We don't calculate implicitWidth unless it is required.
1651 // We need to force a size update now to ensure implicitWidth is calculated
1652 const_cast<QDeclarative1TextEditPrivate*>(this)->requireImplicitWidth = true;
1653 const_cast<QDeclarative1TextEdit*>(q)->updateSize();
1655 return mImplicitWidth;
1658 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1659 // need to do all the calculations each time
1660 void QDeclarative1TextEdit::updateSize()
1662 Q_D(QDeclarative1TextEdit);
1663 if (isComponentComplete()) {
1664 qreal naturalWidth = d->mImplicitWidth;
1665 // ### assumes that if the width is set, the text will fill to edges
1666 // ### (unless wrap is false, then clipping will occur)
1668 if (!d->requireImplicitWidth) {
1669 emit implicitWidthChanged();
1670 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1671 if (d->requireImplicitWidth)
1674 if (d->requireImplicitWidth) {
1675 d->document->setTextWidth(-1);
1676 naturalWidth = d->document->idealWidth();
1678 if (d->document->textWidth() != width())
1679 d->document->setTextWidth(width());
1681 d->document->setTextWidth(-1);
1683 QFontMetrics fm = QFontMetrics(d->font);
1685 dy -= (int)d->document->size().height();
1688 if (heightValid()) {
1689 if (d->vAlign == AlignBottom)
1691 else if (d->vAlign == AlignVCenter)
1698 if (nyoff != d->yoff) {
1699 prepareGeometryChange();
1702 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1704 //### need to comfirm cost of always setting these
1705 int newWidth = qCeil(d->document->idealWidth());
1706 if (!widthValid() && d->document->textWidth() != newWidth)
1707 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1708 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1710 setImplicitWidth(newWidth);
1711 else if (d->requireImplicitWidth)
1712 setImplicitWidth(naturalWidth);
1713 qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
1714 setImplicitHeight(newHeight);
1716 d->paintedSize = QSize(newWidth, newHeight);
1717 setContentsSize(d->paintedSize);
1718 emit paintedSizeChanged();
1725 void QDeclarative1TextEdit::updateTotalLines()
1727 Q_D(QDeclarative1TextEdit);
1731 for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1732 QTextLayout *layout = it.layout();
1735 subLines += layout->lineCount()-1;
1738 int newTotalLines = d->document->lineCount() + subLines;
1739 if (d->lineCount != newTotalLines) {
1740 d->lineCount = newTotalLines;
1741 emit lineCountChanged();
1745 void QDeclarative1TextEditPrivate::updateDefaultTextOption()
1747 Q_Q(QDeclarative1TextEdit);
1748 QTextOption opt = document->defaultTextOption();
1749 int oldAlignment = opt.alignment();
1751 QDeclarative1TextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
1752 if (rightToLeftText) {
1753 if (horizontalAlignment == QDeclarative1TextEdit::AlignLeft)
1754 horizontalAlignment = QDeclarative1TextEdit::AlignRight;
1755 else if (horizontalAlignment == QDeclarative1TextEdit::AlignRight)
1756 horizontalAlignment = QDeclarative1TextEdit::AlignLeft;
1758 opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
1760 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1761 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
1763 if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
1765 document->setDefaultTextOption(opt);
1770 \qmlmethod void QtQuick1::TextEdit::openSoftwareInputPanel()
1772 Opens software input panels like virtual keyboards for typing, useful for
1773 customizing when you want the input keyboard to be shown and hidden in
1776 By default the opening of input panels follows the platform style. On Symbian^1 and
1777 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1778 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1779 always closed if no editor has active focus.
1781 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1782 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1783 the behavior you want.
1785 Only relevant on platforms, which provide virtual keyboards.
1791 text: "Hello world!"
1792 activeFocusOnPress: false
1794 anchors.fill: parent
1796 if (!textEdit.activeFocus) {
1797 textEdit.forceActiveFocus();
1798 textEdit.openSoftwareInputPanel();
1800 textEdit.focus = false;
1803 onPressAndHold: textEdit.closeSoftwareInputPanel();
1808 void QDeclarative1TextEdit::openSoftwareInputPanel()
1810 QEvent event(QEvent::RequestSoftwareInputPanel);
1812 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1813 if (view->scene() && view->scene() == scene()) {
1814 QApplication::sendEvent(view, &event);
1821 \qmlmethod void QtQuick1::TextEdit::closeSoftwareInputPanel()
1823 Closes a software input panel like a virtual keyboard shown on the screen, useful
1824 for customizing when you want the input keyboard to be shown and hidden in
1827 By default the opening of input panels follows the platform style. On Symbian^1 and
1828 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1829 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1830 always closed if no editor has active focus.
1832 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1833 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1834 the behavior you want.
1836 Only relevant on platforms, which provide virtual keyboards.
1842 text: "Hello world!"
1843 activeFocusOnPress: false
1845 anchors.fill: parent
1847 if (!textEdit.activeFocus) {
1848 textEdit.forceActiveFocus();
1849 textEdit.openSoftwareInputPanel();
1851 textEdit.focus = false;
1854 onPressAndHold: textEdit.closeSoftwareInputPanel();
1859 void QDeclarative1TextEdit::closeSoftwareInputPanel()
1861 QEvent event(QEvent::CloseSoftwareInputPanel);
1863 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1864 if (view->scene() && view->scene() == scene()) {
1865 QApplication::sendEvent(view, &event);
1871 void QDeclarative1TextEdit::focusInEvent(QFocusEvent *event)
1873 Q_D(const QDeclarative1TextEdit);
1874 if (d->showInputPanelOnFocus) {
1875 if (d->focusOnPress && !isReadOnly()) {
1876 openSoftwareInputPanel();
1879 QDeclarative1PaintedItem::focusInEvent(event);
1882 void QDeclarative1TextEdit::q_canPasteChanged()
1884 Q_D(QDeclarative1TextEdit);
1885 bool old = d->canPaste;
1886 d->canPaste = d->control->canPaste();
1887 if(old!=d->canPaste)
1888 emit canPasteChanged();